import random
#Classes
#Race Information Source http://gdnd.wikidot.com/races
#Class Information Source http://gdnd.wikidot.com/classes
#Feat Information Source http://gdnd.wikidot.com/feats
#Background Information Source http://gdnd.wikidot.com/backgrounds
#Player Race configuration options
def ChooseStats(Points):#This whole block needs to be tested - tested some, not all
    Options = ["Str","Dex","Con","Int","Wis","Cha"]
    ReturnStats = {}
    statarray = []
    num = 1
    Count = Points
    for x in Options:
        print(num, ". ", x)
        num += 1
    while Count > 0:
        add = input("Choose a stat to increase: ")
        while add.isdigit == 0:
            add = input("Selection must be a number...")
        add = int(add)
        if add == 1:
            statarray.append("Str")
        elif add == 2:
            statarray.append("Dex")
        elif add == 3:
            statarray.append("Con")
        elif add == 4:
            statarray.append("Int")
        elif add == 5:
            statarray.append("Wis")
        elif add == 6:
            statarray.append("Cha")
        Count -= 1
    for x in statarray:
        if x in ReturnStats:
            ReturnStats[x] += 1
        else:
            ReturnStats[x] = 1
    return ReturnStats

class PlayerRace(object):
    class Human():
        SkinColor = ["White", "Tan", "Black","Ginger"]
        Sex = ["Male", "Female"]
        Speed = 30
        Languages = ['Common','Extra']
        class PhysicalTraits():
            Age = random.randint(15,100)     #Years
            Height = random.randint(60,80)   #Inches
            Weight = random.randint(100,300) #Pounds
            Size = "Medium"
        class Proficiency():
            Armor = []
            Weapons = []
            Tools = []
        class Subclass():
            class Normal():
                Name = "Human"
                Stats = {"Str":1,"Dex":1,"Con":1,"Int":1,"Wis":1,"Cha":1}
            class Variant():
                Name = "Human"
                Stats = [] #if this race is chosen, use ChooseStats(2) in main.py

    class Dwarf():
        Name = "Dwarf"
        SkinColor = ["White", "Tan", "Black","Ginger"]
        Sex = ["Male", "Female"]
        Speed = 25
        Languages = ["Common","Dwarvish"]
        Stats = {"Con":2}
        Traits = ["Darkvision","Dwarven Resilience","Dwarven Combat Training","Stonecunning"]
        class PhysicalTraits():
            Age = random.randint(45,350)
            Height = random.randint(48,65)
            Weight = random.randint(120,180)
            Size = "Medium"
        class Proficiency():
            Armor = []
            Weapons = []
            Tools = []
        class subclass():
            class Hill():
                Name = "Hill Dwarf"
                Stats = {"Wis":1,"Hit":1}
                Traits = ["Dwarven Toughness"]
            class Mountain():
                Name = "Mountain Dwarf"

    class Goblin():
        Name = "Goblin"
        SkinColor = ["Green", "Yellow", "Brown"]
        Sex = ["Male", "Female"]
        #Speed =
        #Languages = []
        #Stats = {}
        #Traits = []
        #class PhysicalTraits():
            #Age = random.randint()
            #Height = random.randint()
            #Weight = random.randint()
            #Size = "Medium"
        #class Proficiency():
            #Armor = []
            #Weapons = []
            #Tools = []
        #class subclass():

    class Orc():
        Name = "Orc"
        SkinColor = ["Light Green", "Dark Green"]
        Sex = ["Male", "Female"]
        #Speed =
        #Languages = []
        #Stats = {}
        #Traits = []
        #class PhysicalTraits():
            #Age = random.randint()
            #Height = random.randint()
            #Weight = random.randint()
            #Size = "Medium"
        #class Proficiency():
            #Armor = []
            #Weapons = []
            #Tools = []
        #class subclass():

    class HalfOrc():
        Name = "Half Orc"
        #SkinColor = []
        #Sex = ["Male","Female"]
        #Speed =
        #Languages = []
        #Stats = {}
        #Traits = []
        #class PhysicalTraits():
            #Age = random.randint()
            #Height = random.randint()
            #Weight = random.randint()
            #Size = "Medium"
        #class Proficiency():
            #Armor = []
            #Weapons = []
            #Tools = []
        #class subclass():

    class Dragonborn():
        Name = "Dragonborn"
        #SkinColor = []
        #Sex = ["Male","Female"]
        #Speed =
        #Languages = []
        #Stats = {}
        #Traits = []
        #class PhysicalTraits():
            #Age = random.randint()
            #Height = random.randint()
            #Weight = random.randint()
            #Size = "Medium"
        #class Proficiency():
            #Armor = []
            #Weapons = []
            #Tools = []
        #class subclass():

    class Elf():
        Name = "Elf"
        #SkinColor = []
        #Sex = ["Male","Female"]
        #Speed =
        #Languages = []
        #Stats = {}
        #Traits = []
        #class PhysicalTraits():
            #Age = random.randint()
            #Height = random.randint()
            #Weight = random.randint()
            #Size = "Medium"
        #class Proficiency():
            #Armor = []
            #Weapons = []
            #Tools = []
        #class subclass():

    class HalfElf():
        Name = "Half Elf"
        #SkinColor = []
        #Sex = ["Male","Female"]
        #Speed =
        #Languages = []
        #Stats = {}
        #Traits = []
        #class PhysicalTraits():
            #Age = random.randint()
            #Height = random.randint()
            #Weight = random.randint()
            #Size = "Medium"
        #class Proficiency():
            #Armor = []
            #Weapons = []
            #Tools = []
        #class subclass():

    class Gnome():
        Name = "Gnome"
        #SkinColor = []
        #Sex = ["Male","Female"]
        #Speed =
        #Languages = []
        #Stats = {}
        #Traits = []
        #class PhysicalTraits():
            #Age = random.randint()
            #Height = random.randint()
            #Weight = random.randint()
            #Size = "Medium"
        #class Proficiency():
            #Armor = []
            #Weapons = []
            #Tools = []
        #class subclass():

    class Halfling():
        Name = "Halfling"
        #SkinColor = []
        #Sex = ["Male","Female"]
        #Speed =
        #Languages = []
        #Stats = {}
        #Traits = []
        #class PhysicalTraits():
            #Age = random.randint()
            #Height = random.randint()
            #Weight = random.randint()
            #Size = "Medium"
        #class Proficiency():
            #Armor = []
            #Weapons = []
            #Tools = []
        #class subclass():

    class Tiefling():
        Name = "Tiefling"
        #SkinColor = []
        #Sex = ["Male","Female"]
        #Speed =
        #Languages = []
        #Stats = {}
        #Traits = []
        #class PhysicalTraits():
            #Age = random.randint()
            #Height = random.randint()
            #Weight = random.randint()
            #Size = "Medium"
        #class Proficiency():
            #Armor = []
            #Weapons = []
            #Tools = []
        #class subclass():

class PlayerJobs(object):
    class Barbarian():
        Name = "Barbarian"
        HitPoints = 12
        class proficiency():
            Armor = ["Light","Medium","Shield"]
            Weapons = ["Simple","Martial"]
            Tools = []
    class Bard():
        Name = "Bard"
        HitPoints = 0
        class proficiency():
            Armor = []
            Weapons = []
            Tools = []
    class Cleric():
        Name = "Cleric"
        HitPoints = 0
        class proficiency():
            Armor = []
            Weapons = []
            Tools = []
    class Druid():
        Name = "Druid"
        HitPoints = 0
        class proficiency():
            Armor = []
            Weapons = []
            Tools = []
    class Fighter():
        Name = "Fighter"
        HitPoints = 0
        class proficiency():
            Armor = []
            Weapons = []
            Tools = []
    class Monk():
        Name = "Monk"
        HitPoints = 0
        class proficiency():
            Armor = []
            Weapons = []
            Tools = []
    class Paladin():
        Name = "Paladin"
        HitPoints = 0
        class proficiency():
            Armor = []
            Weapons = []
            Tools = []
    class Ranger():
        Name = "Ranger"
        HitPoints = 0
        class proficiency():
            Armor = []
            Weapons = []
            Tools = []
    class Rogue():
        Name = "Rogue"
        HitPoints = 0
        class proficiency():
            Armor = []
            Weapons = []
            Tools = []
    class Sorceror():
        Name = "Sorceror"
        HitPoints = 0
        class proficiency():
            Armor = []
            Weapons = []
            Tools = []
    class Warlock():
        Name = "Warlock"
        HitPoints = 0
        class proficiency():
            Armor = []
            Weapons = []
            Tools = []
    class Wizard():
        Name = "Wizard"
        HitPoints = 0
        class proficiency():
            Armor = []
            Weapons = []
            Tools = []

class PlayerBackground():
    class Hermit():
        Name = "Hermit"

class Feats():
    class Actor():
        Name = "Actor"
        Stats = {"Cha":1}
        Bonuses = ["You can mimic the speech of another person or the sounds\
                 made by other creatures. You must have heard the person\
                 speaking, or heard the creature make the sound, for at least\
                 1 minute. A successful Wisdom (Insight) check contested by your\
                 Charisma (Deception) check allows a listener to determine that \
                 the effect is faked."]


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

from PyQt5 import QtCore, QtGui, QtWidgets
from qgis.core import *
from qgis.core import QgsVectorFileWriter, QgsWkbTypes
import ntpath
import os
from scipy.spatial import ConvexHull
import numpy as np
from math import sqrt, pow

class Ui_dlgKmean(QDialog):
    def __init__(self):
        QDialog.__init__(self)
        self.setObjectName("self")
        self.resize(400, 188)
        self.setAutoFillBackground(False)

        self.lnEditCsvPath = QtWidgets.QLineEdit(self)
        self.lnEditCsvPath.setGeometry(QtCore.QRect(10, 30, 381, 20))
        self.lnEditCsvPath.setText("C:/")

        self.lnEditCsvPath.setObjectName("lnEditCsvPath")
        self.btnOpen = QtWidgets.QPushButton("Open",self)
        self.btnOpen.setGeometry(QtCore.QRect(300, 60, 92, 25))
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.btnOpen.sizePolicy().hasHeightForWidth())
        self.btnOpen.setSizePolicy(sizePolicy)
        self.btnOpen.setMinimumSize(QtCore.QSize(92, 0))

        self.btnOpen.setObjectName("btnOpen")
        self.label_3 = QtWidgets.QLabel("Import CSV data:",self)
        self.label_3.setGeometry(QtCore.QRect(10, 10, 141, 16))
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self.label_3.setFont(font)
        self.label_3.setObjectName("label_3")
        self.label_4 = QtWidgets.QLabel("Number of clusters:",self)
        self.label_4.setGeometry(QtCore.QRect(10, 90, 151, 16))
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self.label_4.setFont(font)
        self.label_4.setObjectName("label_4")
        self.spinBox = QtWidgets.QSpinBox(self)
        self.spinBox.setValue(1)
        self.spinBox.setGeometry(QtCore.QRect(10, 110, 51, 22))

        self.spinBox.setObjectName("spinBox")
        self.btnRUN = QtWidgets.QPushButton("RUN",self)
        self.btnRUN.setGeometry(QtCore.QRect(120, 150, 71, 28))
        font = QtGui.QFont()
        font.setPointSize(-1)
        self.btnRUN.setFont(font)

        self.btnRUN.setObjectName("btnRUN")
        self.btnCancel = QtWidgets.QPushButton("CANCEL",self)
        self.btnCancel.setGeometry(QtCore.QRect(210, 150, 71, 28))
        font = QtGui.QFont()
        font.setPointSize(-1)
        self.btnCancel.setFont(font)

        self.btnCancel.setObjectName("btnCancel")

        self.btnRUN.clicked.connect(self.run)
        self.btnCancel.clicked.connect(self.cancel)
        self.btnOpen.clicked.connect(self.open)

        QtCore.QMetaObject.connectSlotsByName(self)

    def open(self):
        initPath = self.lnEditCsvPath.text()
        print (initPath)
        path, _ = QFileDialog.getOpenFileName(self,"Open GPS data",initPath,"*.csv")

        import os

        filePath = path.rstrip(os.sep)

        self.lnEditCsvPath.setText(str(filePath))

    def loadCsv(self):
        Input_Table = self.lnEditCsvPath.text()  # set the filepath for the input CSV
        lon_field = 'origin_lon'  # set the name for the field containing the longitude
        lat_field = 'origin_lat'  # set the name for the field containing the latitude
        lon_dest = 'dest_lon'
        lat_dest = 'dest_lat'

        crs = 4326  # WGS 84 (GPS data)
        strCRS = "EPSG" + str(4326)

        directory = os.path.dirname(Input_Table) + "/output"

        import time
        # timestamp = time.time()
        ts = time.gmtime()
        ts = time.strftime("%Y%m%dT%H%M%S", ts)

        filename = ntpath.basename(self.lnEditCsvPath.text()).replace(".csv", "") + "_" + ts + "_" + strCRS + ".shp"

        if not os.path.exists(directory):
            os.makedirs(directory)

        outputLayerPath = directory + "//" + filename  # set the filepath for the output shapefile

        #print (outputLayerPath)

        spatRef = QgsCoordinateReferenceSystem(crs, QgsCoordinateReferenceSystem.EpsgCrsId)

        inp_tab = QgsVectorLayer(Input_Table, 'Input_Table', 'ogr')
        prov = inp_tab.dataProvider()
        fields = inp_tab.fields()
        outLayer = QgsVectorFileWriter(outputLayerPath, None, fields, QgsWkbTypes.Point, spatRef, "ESRI Shapefile")
        # outLayer = QgsVectorFileWriter(Output_Layer, None, fields, QGis.WKBPoint, spatRef)

        # reprojecting to metric datum system for k-means clustering purposes

        pt = QgsPointXY()
        pt_dest = QgsPointXY()

        outFeature = QgsFeature()
        outFeature_dest = QgsFeature()

        for feat in inp_tab.getFeatures():
            attrs = feat.attributes()
            pt.setX(float(feat[lon_field]))
            pt.setY(float(feat[lat_field]))
            outFeature.setAttributes(attrs)
            outFeature.setGeometry(QgsGeometry.fromPointXY(pt))
            outLayer.addFeature(outFeature)

            pt_dest.setX(float(feat[lon_dest]))
            pt_dest.setY(float(feat[lat_dest]))
            outFeature_dest.setAttributes(attrs)
            outFeature_dest.setGeometry(QgsGeometry.fromPointXY(pt_dest))
            outLayer.addFeature(outFeature_dest)

        del outLayer
        return outputLayerPath
        # import processing

    def changeLayerCrs(self, outputLayerPath):
        rootPath=os.path.dirname(outputLayerPath)

        crs = 4326  # WGS 84 (GPS data)
        strCRS = "EPSG" + str(4326)
        destCRS = 3857
        spatRefDest = QgsCoordinateReferenceSystem(destCRS, QgsCoordinateReferenceSystem.EpsgCrsId)

        # print (spatRefDest)

        strDestCRS = "EPSG" + str(destCRS)  # PSEUDO MERCATOR PROJECTION

        # outputLayerDestPath = outputLayerPath.replace(strCRS, strDestCRS)
        # print (outputLayerDestPath)
        filename=ntpath.basename(outputLayerPath)

        filename_dest = filename.replace(strCRS, strDestCRS)

        # self.reprojectLyr(Output_Layer,Output_Layer_dest, strDestCRS)

        # parameter = {'INPUT': Output_Layer,'TARGET_CRS': "EPSG:3857",'OUTPUT':Output_Layer_dest}

        # processing.run('qgis:reprojectlayer', parameter)
        layerName = filename.replace(".shp", "")
        outputLayerDestPath=rootPath+'//'+layerName+'_NEW_3857.shp'

        outputLoad = QgsVectorLayer(outputLayerPath, layerName, 'ogr')
        # if not layer.isValid():
        # raise IOError, "Failed to open the layer"

        # add layer to the registry
        QgsProject.instance().addMapLayer(outputLoad)
        canvas = QgsMapCanvas()
        # set extent to the extent of our layer
        canvas.setExtent(outputLoad.extent())
        canvas.setLayers([outputLoad])
        canvas.refresh()

        exp_crs = QgsCoordinateReferenceSystem(3857, QgsCoordinateReferenceSystem.EpsgCrsId)

        # canvas = qgis.utils.iface.mapCanvas()
        #allLayers = canvas.layers()
        layer = QgsProject.instance().mapLayersByName(layerName)[0]

        qgis.core.QgsVectorFileWriter.writeAsVectorFormat(layer, outputLayerDestPath, 'utf-8', exp_crs, "ESRI Shapefile")

        layerName_3857 = layerName + '_NEW_3857.shp'

        outputLoad3857 = QgsVectorLayer(outputLayerDestPath, layerName_3857.replace('.shp',''), 'ogr')

        id = layer.id()

        QgsProject.instance().removeMapLayer(id)

        QgsProject.instance().addMapLayer(outputLoad3857)

        # set extent to the extent of our layer
        canvas.setExtent(outputLoad3857.extent())
        canvas.setLayers([outputLoad3857])

        selectedcrs = "EPSG:3857"
        target_crs = QgsCoordinateReferenceSystem()
        target_crs.createFromUserInput(selectedcrs)
        canvas.setDestinationCrs(target_crs)

        canvas.refresh()

        return outputLoad3857

    def getCoords(self, layer):
        import numpy as np
        print ("getting cords from layer: " + layer)
        outputFieldName = 'cluster_no'
        layerProc = QgsProject.instance().mapLayersByName(layer)[0]

        coordsList = []

        from PyQt5.QtCore import QVariant
        layer_provider = layerProc.dataProvider()
        layer_provider.addAttributes([QgsField(outputFieldName, QVariant.Int)])

        layerProc.updateFields()

        for feature in layerProc.getFeatures():
            geom = feature.geometry()
            x = geom.centroid().asPoint().x()
            y = geom.centroid().asPoint().y()
            coordsList.append([x, y])

        data = np.array(coordsList)
        return data

    def kmeans(self, layer, data, noClusters):
        print ("K-means clustering. Processing layer: " + layer + ". Number of clusters: k = " + str(noClusters))
        outputFieldName = 'cluster_no'
        layerProc = QgsProject.instance().mapLayersByName(layer)[0]
        from scipy.cluster.vq import kmeans, vq

        centroids, _ = kmeans(data, noClusters)
        idx, _ = vq(data, centroids)
        idx = idx.tolist()
        # Create CLUSTER_NO field of not exist

        layerProc.startEditing()

        i = 0

        print ("Wait until DONE.........")

        for f in layerProc.getFeatures():
            f[outputFieldName] = int(idx[i] + 1)
            layerProc.updateFeature(f)
            # layer_provider.changeAttributeValue(feature.id(), attrIdx, int(idx[i]))
            i += 1

        print ("DONE")

        layerProc.updateFields()
        layerProc.commitChanges()

    def createConvHullLayer(self,path):
        rootPath = os.path.dirname(path)
        filename = ntpath.basename(path)
        filename=filename.replace('.shp','_conv.shp')
        convLayerPath = os.path.join(rootPath, filename)
        crs1=3857

        vl = QgsVectorLayer("Polygon?crs=epsg:" + str(crs1), "convexHull", "memory")
        pr = vl.dataProvider()

        # Enter editing mode
        vl.startEditing()

        pr.addAttributes([QgsField('No.', QVariant.Int), QgsField('Area[m]', QVariant.Double, 'double', 12, 2),
                          QgsField('pointsNum', QVariant.Int), QgsField('Density', QVariant.Double, 'double', 12, 2),
                          QgsField('AvgDist', QVariant.Double, 'double', 12, 2)])

        # Commit changes
        vl.commitChanges()

        crs_writer = QgsCoordinateReferenceSystem("epsg:" + str(crs1))

        # zapis
        _writer = QgsVectorFileWriter.writeAsVectorFormat(vl, convLayerPath, "utf-8", crs_writer, "ESRI Shapefile")

        return convLayerPath

    def calculateAverageDistance(self,hullTmp, layer):
        cx = np.mean(hullTmp.points[hullTmp.vertices, 0])
        cy = np.mean(hullTmp.points[hullTmp.vertices, 1])
        cPoint = QgsPointXY(cx, cy)
        print (cPoint)
        total=0.0
        n=0
        for feat in layer.getSelectedFeatures():
            geom = feat.geometry()
            px = geom.centroid().asPoint().x()
            py = geom.centroid().asPoint().y()
            pPoint=QgsPointXY(px, py)
            print (pPoint)

            # Create a measure object
            distance = QgsDistanceArea()
            #distance.setEllipsoidalMode(True)
            distance.setEllipsoid('WGS84')
            # Measure the distance
            length=sqrt(pow((cx-px),2)+pow((cy-py),2))#distance.measureLine(cPoint, pPoint)
            total+=length
            n+=1

        avgDist=total/n
        return avgDist

    def convHulls(self, layer, noClusters):

        outputFieldName = 'cluster_no'
        layerProc = QgsProject.instance().mapLayersByName(layer)[0]
        print ("CONV HULLS", layerProc.name(), noClusters, outputFieldName)

        convLayerPath = self.createConvHullLayer(layerProc.source())

        vectorLyr = QgsVectorLayer(convLayerPath, 'convexhull_'+layerProc.name(),"ogr")

        QgsProject.instance().addMapLayer(vectorLyr)

        vpr = vectorLyr.dataProvider()

        vectorLyr.startEditing()

        for i in range(1, noClusters + 1):

            # exp = "'" + '"cluster_no\"=' + str(i) + "'"
            exp = '"cluster_no\"=' + str(i)
            print (exp)

            layerProc.selectByExpression(exp, QgsVectorLayer.SetSelection)

            coordListTmp = []
            #
            for feat in layerProc.getSelectedFeatures():
                geom = feat.geometry()
                x = geom.centroid().asPoint().x()
                y = geom.centroid().asPoint().y()
                # print (feat.id(),x,y)

                coordListTmp.append([x, y])

            points2 = coordListTmp  # np.array(coordListTmp)
            pointsNumber=len(coordListTmp)
            listAr = np.array(points2)

            hullTmp = ConvexHull(listAr)
            avgDist=self.calculateAverageDistance(hullTmp, layerProc)

            hullPointsTmp = hullTmp.points[hullTmp.vertices]

            wktGeometry='POLYGON (('
            for point in hullPointsTmp:
                wktPoint=str(point[0])+' '+str(point[1])
                wktGeometry+=wktPoint+','

            wktGeometry=wktGeometry[:-1]+'))'
            poly = QgsGeometry.fromWkt(wktGeometry)

            f = QgsFeature()
            f.setGeometry(poly)
            area=f.geometry().area()
            density=area/pointsNumber
            f.setAttributes([i,area,pointsNumber,density,avgDist])
            vpr.addFeatures([f])

            i += 1
        vectorLyr.commitChanges()
        iface.mapCanvas().refresh()

    def saveReport(self,layerPath, noClusters):
        reportPath=layerPath.replace('.shp','_report.txt')
        name= (ntpath.basename(layerPath)).replace('.shp','')
        content='Name: '+name+'\nMethod: K-means\nNumber of clusters: '+str(noClusters)
        with open(reportPath,'w',encoding='utf-8') as file:
            file.write(content)
    def run(self):

        noClusters = self.spinBox.value()

        if noClusters > 25 or noClusters == 0:
            print ("Number of clusters can't be greater than 25 or smaller than 1")

        if noClusters <= 25 and noClusters > 0:
            outputLayerPath=self.loadCsv()
            print ("CSV data has been imported")
            mainLayer=self.changeLayerCrs(outputLayerPath)
            corArray = self.getCoords(mainLayer.name())
            self.kmeans(mainLayer.name(), corArray, noClusters)
            self.convHulls(mainLayer.name(),noClusters)
            self.saveReport(mainLayer.source(),noClusters)
            dialog.hide()
            #self.kmeans(layerName_3857, corArray, noClusters)

    def cancel(self):
        print ("cancel")
        dialog.hide()

dialog = Ui_dlgKmean()

if dialog.exec_() == QDialog.Accepted:

    print ("ACC")


from xai.brain.wordbase.nouns._paragraph import _PARAGRAPH

#calss header
class _PARAGRAPHED(_PARAGRAPH, ):
	def __init__(self,):
		_PARAGRAPH.__init__(self)
		self.name = "PARAGRAPHED"
		self.specie = 'nouns'
		self.basic = "paragraph"
		self.jsondata = {}


# analyze_particulate_data.py
#   by: Nick Dow
# ***************************** Run Notes ***************************** #
# - Save peak particulate density for each test in a table:
# 		/05_Charts/Particulate/maxParticulateSummary.csv
# ********************************************************************* #

# -------------- #
# Import Modules #
# -------------- #
import os
import pandas as pd
import numpy as np

# ---------------------------------- #
# Define Subdirectories & Info Files #
# ---------------------------------- #
info_dir = '../03_Info/'
data_dir = '../02_Data/Particulate/'
results_dir = '../05_Charts/'

# Create results directory if necessary
if not os.path.exists(results_dir):
	os.makedirs(results_dir)

# Read in exp info file
exp_info = pd.read_csv(info_dir + 'Particulate_Info.csv', index_col='Test_Name')

# create dataframe for max values
summDataHeaders = ['Test_Name',
					'PM1_max', 'PM1_avg',
					'PM2.5_max', 'PM2.5_avg',
					'RESP_max', 'RESP_avg',
					'PM10_max', 'PM10_avg',
					'TOTAL_max', 'TOTAL_avg',
					'Time_at_max']
summData = pd.DataFrame(columns=summDataHeaders)

# ------------------------------ #
# Start Code Used to Import Data #
# ------------------------------ #

# Determine which test data to plot
data_file_ls = []
# loop through 02_Data/Particulate/ directory
for f in os.listdir(data_dir):
	if not f.startswith('Burn'): continue

	# file path to sub directories (i.e. 02_Data/Particulate/Burn1_29SEP2020/)
	exp_dir = os.path.join(data_dir,f)

	# loop through subdirectory
	for ff in os.listdir(exp_dir):

		# check for another level of subdirectory (i.e. '1 Day Post')
		if os.path.isdir(os.path.join(exp_dir,ff)):
			exp_subdir = os.path.join(exp_dir,ff)

			# loop through 'X Day Post' directory and add any excel files to list of file paths
			for fff in os.listdir(exp_subdir):
				if fff.endswith('.xlsx'):
					filepath = os.path.join(exp_subdir,fff)
					data_file_ls.append(filepath)

		# add any excel files to list of file paths
		if ff.endswith('.xlsx'):
			filepath = os.path.join(exp_dir,ff)
			data_file_ls.append(filepath)

# Loop through test data files
for f in data_file_ls:
	filepath = f.split('/')[2:-1]
	filepath = '/'.join(filepath)

	# Get test name from file
	Test_Name = f.split('/')[-1][:-5]

	# Read in data for experiment
	Exp_Data = pd.read_excel(f, skiprows=28, usecols=[1,2,3,4,5,6], names=['Timestamp','PM1','PM2.5','RESP','PM10','TOTAL'])
	print ('--- Loaded data file for '+Test_Name+' ---')

	# check exp_info file to see if need to skip lines in data
	# skip_lines format must be comma separated and splices separated by colon
	if Test_Name in exp_info.index.values:
		# import Skip_Lines values from exp_info file
		skip_str = exp_info['Skip_Lines'][Test_Name]

		# split comma separated values if possible
		try: skip_list = skip_str.split(',')
		except: skip_list = [skip_str]

		# loop through Skip_Lines values
		for i in skip_list:
			# split colon separated values if possible
			try:
				j,k = i.split(':')
				skip_idx = list(range(int(j),int(k)+1))
			except:
				skip_idx = [int(i)]

			# remove rows from data frame according to Skip_Lines values
			Exp_Data.drop(skip_idx, inplace=True)

	# add desired values to summary dataframe
	rowData = [Test_Name, max(Exp_Data['PM1']), Exp_Data['PM1'].mean(),
		max(Exp_Data['PM2.5']), Exp_Data['PM2.5'].mean(),
		max(Exp_Data['RESP']), Exp_Data['RESP'].mean(),
		max(Exp_Data['PM10']), Exp_Data['PM10'].mean(),
		max(Exp_Data['TOTAL']), Exp_Data['TOTAL'].mean(),
		Exp_Data['TOTAL'].idxmax()]
	summData = summData.append(pd.DataFrame([rowData], columns=summDataHeaders))
# avg values

# sort and index dataframe
summData = summData.sort_values(by='Test_Name')
summData = summData.set_index([pd.Index(range(0,len(summData)))])
# print (summData)
print()
summData.to_csv(results_dir + 'Particulate/maxParticulateSummary.csv')


# -*- coding: utf-8 -*-
"""
@Description:

@Author: AweSong-Kor
@Github: AweSong-Kor/Machine-Learning/Models
"""

import tensorflow as tf
import numpy as np
import tf_wrappers as fn

# Define simpleCNN Class
class simpleCNN:
	def __init__(self, session, input_shape, output_size=2, name="main"):
		self.session = session
		self.input_w = input_shape[0]
		self.input_h = input_shape[1]
		self.input_ch = input_shape[2]
		self.output_size = output_size
		self.net_name = name
		self.build_network()

	def build_network(self, l_rate=1e-4):
		with tf.variable_scope(self.net_name):
			self._X = tf.placeholder(tf.float32, [None,self.input_w,self.input_h,self.input_ch], name="input_x")
			# First layer
			W1 = fn.weight_variable([3, 3, self.input_ch, 32],"W1")
			b1 = fn.bias_variable([32],"b1")
			layer1 = tf.nn.relu(fn.conv2d(self._X,W1) + b1)
			# Second layer
			W2 = fn.weight_variable([3, 3, 32, 1],"W2")
			b2 = fn.bias_variable([1],"b2")
			layer2 = tf.nn.relu(fn.conv2d(layer1,W2) + b2)

			# Max Pooling layer
			max_pool = fn.max_pool_3x3_V(layer2)

			# Fully-Connected layer
			fc_input = tf.reshape(max_pool, [-1, 14*14])
			W_fc = fn.weight_variable([14*14,self.output_size],"W_fc")
			b_fc = fn.bias_variable([self.output_size],"b_fc")

			# Q prediction
			self._Ypred = tf.matmul(fc_input, W_fc) + b_fc

		# We need to define the parts of the network needed for learning a policy
		self._Y = tf.placeholder(shape=[None, self.output_size], dtype=tf.float32)

		# Loss function
		# mean square error
		# self._loss = tf.reduce_mean(tf.square(self._Y - self._Ypred))
		# cross_entropy
		cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits=self._Ypred,labels=self._Y)
		self._loss = tf.reduce_mean(cross_entropy)

		# Learning
		self._train = tf.train.AdamOptimizer(learning_rate=l_rate).minimize(self._loss)

		# Add ops to save and restore all the variables.
		self._saver = tf.train.Saver()

	def predict(self, input_x):
		x = np.reshape(input_x, [1, self.input_w, self.input_h, self.input_ch])
		return self.session.run(self._Ypred, feed_dict={self._X: x})

	def update(self, x_stack, y_stack):
		return self.session.run([self._loss, self._train], feed_dict={self._X: x_stack, self._Y: y_stack})

	def save(self,sess,save_path):
		return self._saver.save(sess,save_path)


class Solution:
    def judgeCircle(self, moves: str) -> bool:
        dic = dict()
        for i,v in enumerate(moves):
            dic[v] = dic.get(v, 0) + 1

        if dic.get("U") == dic.get("D") and dic.get("L") == dic.get("R"):
            return True
        else:
            return False

sol = Solution()
sol.judgeCircle("UD")


# Need to do that for tflite and need to do it before importing tensorflow
import os
os.environ['TF_ENABLE_CONTROL_FLOW_V2'] = '1'

import sofilstm.sofi as sofi
import sofilstm.train as train
from sofilstm import image_util_preprocess

import scipy.io as spio
import numpy as np
import os
from sys import platform
# This is taken from the ScaDec from Ulugbek Kamilov 2018 et al. which is a copy of the tf_unet

import tensorflow as tf

tf.reset_default_graph()
####################################################
####              HYPER-PARAMETERS               ###
####################################################

# Because we have real & imaginary part of our input, data_channels is set to 2
features_root = 4
# args for training
batch_size = 4     # batch size for training
Ntime = 20    # number of time-steps for one 3D volume
optimizer = "adam"  # optimizer we want to use, 'adam' or 'momentum'
Nx, Ny = 256, 256 # final size of the image

learning_rate = 0.01
display_step = 50
epochs = 300
training_iters = 200
save_epoch = 5
dropout = 0.8

# here indicating the GPU you want to use. if you don't have GPU, just leave it.
gpu_ind = '0,1'
os.environ['CUDA_VISIBLE_DEVICES'] = gpu_ind; # 0,1,2,3

####################################################
####                DATA LOADING                 ###
####################################################

# Specify the location with for the training data #
if platform == "linux" or platform == "linux2":
	train_data_path = './data/data_downconverted'; upscaling=2 # linux
elif platform == "darwin":
	train_data_path = './test'; upscaling=4 # OS X
elif platform == 'win32':
   train_data_path = '.\\data\\data_downconverted_2'; upscaling=2
   train_data_path = '.\\data\\data_downconverted_2'; upscaling=2
   train_data_path = '.\\data\\data_raw'; upscaling=1
   train_data_path = '.\\data\\data'; upscaling=2
nn_name = 'upsamping_'+str(upscaling)+'_lstm4_'+str(Nx)+'x'+str(Ny)+'_time_'+str(Ntime)+'_batchnorm_newdataprovider_subpixel_peep_varyingdim_noL1_5'

# Specify the location with for the validation data #
data_provider = image_util_preprocess.ImageDataProvider(train_data_path, nchannels = 1,
                mysize=(Nx, Ny), Ntime=Ntime, downscaling=upscaling, test=False, \
                n_modes = 50, mode_max_angle = 15, n_photons = 100, n_readnoise = 10,
                kernelsize=1, quality_jpeg=80)

valid_provider = image_util_preprocess.ImageDataProvider(train_data_path, nchannels = 1,
                mysize=(Nx, Ny), Ntime=Ntime, downscaling=upscaling, test=False, \
                n_modes = 50, mode_max_angle = 15, n_photons = 100, n_readnoise = 10,
                kernelsize=1, quality_jpeg=80)

####################################################
####                  NETWORK                    ###
####################################################

"""
	here we specify the neural network.

"""

#-- Network Setup --#
# set up args for the unet

net = sofi.SOFI(Nx=Nx, Ny=Ny, batchsize=batch_size, features_root=features_root, Ntime=Ntime)

####################################################
####                 TRAINING                    ###
####################################################
#tensorboard --logdir=.\

# output paths for results
output_root = 'networks/'
output_path = output_root+ nn_name+'_gpu' + gpu_ind + '/models'
prediction_path = output_root + nn_name+'_gpu' + gpu_ind + '/validation'

# make a trainer for muscat
trainer = train.trainer_sofi(net, batch_size=batch_size, optimizer = "adam")

# train
path = trainer.train(data_provider, output_path, valid_provider, batch_size, dropout=dropout, training_iters=training_iters, epochs=epochs, display_step=display_step, save_epoch=save_epoch, prediction_path=prediction_path)


# steps come in form of [(from, into)]
# results come in form of [list_of_deleted_branches]

STAGES = {
	0: {
		'steps': [
			('one', 'master'),
			('two', 'master'),
			('master', 'staging')
		],
		'results': ['one', 'two']
	},
	1: {
		'steps': [
			('three', 'staging')
		],
		'results': []
	},
	2: {
		'steps': [
			('staging', 'master')
		],
		'results': ['staging', 'three']
	},
	3: {
		'steps': [
			('into-master', 'master'),
			('into-into-master-not-master', 'into-master')
		],
		'results': ['into-master']
	}
}

def get_deleted_previously(actual):
	# helper, returns the expected deleted branches
	# for previous stages
	res = []
	while actual > 0:
		actual -= 1
		res += STAGES[actual]['results']

	return res


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Jun 15 16:17:58 2018

@author: jimmyhomefolder
"""

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
df = pd.read_csv("data/student_data.csv")
df_pred = df

label = 'Sauna' #要預測的 label
staying = 'Staying'
features = list(set(df.columns) - {label,
                 'Name',
                 'Address',
                 'Working',
                 'Age of Parent',
                 'Consuming Power',
                 'Beauty',
                 'Purchased',
                 'Massage',
                 'Resource',
                 'Birth Date',
                 'Register Date'
                 })

#%%
# Encoding categorical data (we have string in our data type)
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
X_0 = LabelEncoder()
df['County'] = X_0.fit_transform(df['County'])
df['District'] = X_0.fit_transform(df['District'])
df['Road'] = X_0.fit_transform(df['Road'])
df['Sex'] = X_0.fit_transform(df['Sex'])
#X['Consuming Power'] = X_0.fit_transform(X['Consuming Power'])
#X['Resource '] = X_0.fit_transform(X['Resource '])
#X['Sentimental'] = X_0.fit_transform(X['Sentimental'])

#%%
#df['Birth Date'] = pd.to_datetime(df['Birth Date'])
#df['Register Date'] = pd.to_datetime(df['Register Date'])
df = df.loc[df[staying].notnull()] # 我覺得staying 是個很強的特徵，先用它有值的資料來做預測 看看效果
df_staying_notnull = df
df = df.loc[df[label].notnull() ] # 要預測的 label
X = df[features] #metrics of features
y = df[label].values # independent variable vector(outcome) #Label Column

#%%
# Splitting the dataset into the Training set and Test set
from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, random_state = 0)

# Feature Scaling
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)

#%%
# Fitting Logistic Regression to the Training set

import keras
from keras.models import Sequential #used to initialize our neural network
from keras.layers import Dense # used to create layers in our neural network
from keras.layers import Dropout

from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.naive_bayes import GaussianNB

"""
input_dim = len(X.columns)
classifier = Sequential() # classifier is the future ann we r going to build
classifier.add(Dense(units = 6, kernel_initializer = 'uniform', activation = 'relu', input_dim = input_dim))
#classifier.add(Dense(units = 6, kernel_initializer = 'uniform', activation = 'relu'))
classifier.add(Dense(units = 1, kernel_initializer = 'uniform', activation = 'sigmoid'))
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])
classifier.fit(X_train, y_train, batch_size = 1, epochs = 25)

classifier = GaussianNB()
classifier = DecisionTreeClassifier(criterion = 'entropy', random_state = 0)
classifier = RandomForestClassifier(n_estimators = 10, criterion = 'entropy', random_state = 0)
classifier = SVC(kernel = 'rbf', random_state = 0)
classifier = KNeighborsClassifier(n_neighbors = 5, metric = 'minkowski', p = 2)
classifier = LogisticRegression(random_state = 0)
"""

classifier = LogisticRegression(random_state = 0)

classifier.fit(X_train, y_train)
y_pred = classifier.predict(X_test)

#%%
# Making the Confusion Matrix(it is a function)
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_test, y_pred.round())

#%%
### Predicting...
df_pred = df_pred.loc[df_pred[staying].notnull()] # 我覺得staying 是個很強的特徵，先用它有值的資料來做預測 看看效果
X_pred = df_pred[features] #metrics of features
X_pred_df = X_pred

#%%
X_pred = X_pred.values #change pandas into numpy

Sauna_prediction = []
for i in X_pred[0:]:
    new_prediction = classifier.predict(sc.transform(np.array([list(i)])))
    new_prediction = (new_prediction > 0.5)
    Sauna_prediction.append(new_prediction)

#%%
df_pred['Sauna_prediction'] = Sauna_prediction
df_pred.to_excel('Sauna_prediction.xlsx')


is_on = False

class LightSwitch:
    is_on = False

    def flip(self):
        self.is_on = not self.is_on # field
        print(self.is_on)

    def flipMany(self, number : int):
        for i in range(number):
            self.flip()

def MultiplyByTwo(number: int):
    return number*2

living_room_light = LightSwitch()
bedroom_light = LightSwitch()

print('living_room_light:')
living_room_light.flipMany(13)

# print('bedroom_light:')
# bedroom_light.flip()

# result = MultiplyByTwo(2)
# print(result)

print(type(bedroom_light))
print(dir(bedroom_light))


class Point:
    """
    This test class. Name: Point.
    """
    name = 'Point'

    x = 34
    y = 25

    # def test():
    #     pass

    def __init__(self, x=0, y=0):
        """

        :param x: irtuyrpoitoire
        :param y: erpituygeriuygeiruoh
        """
        self.X = x
        self.Y = y

    def __add__(self, other):
        print('Сумма')

    def show_attr_class(self):
        print("Attr of class 'name':", self.__class__.name)
        print("Attr of class 'x':", self.__class__.x)
        print("Attr of class 'y':", self.__class__.y)

    def show_attr_obj(self):
        print("Attr of object 'X':", self.X)
        print("Attr of object 'Y':", self.Y)

pt1 = Point(3, 4)
pt1.show_attr_obj()
pt1.show_attr_class()

pt2 = Point()
pt2.show_attr_obj()
pt2.show_attr_class()
print('-' * 120)
pt1.X = 12
pt1.Y = 90
pt1.show_attr_obj()
pt1.show_attr_class()
pt2.show_attr_obj()
pt2.show_attr_class()

Point.name = 'Test'
Point.x = 0
print('-' * 120)
pt1.show_attr_obj()
pt1.show_attr_class()
pt2.show_attr_obj()
pt2.show_attr_class()

pt3 = pt1 + pt2

print(Point.__doc__)
help(Point.__init__)
print(Point.__dict__)
print(Point.__bases__)

class SomeClass:
    pass

def square_method(self):
    return self.x ** 2

def init(self, x):
    self.x = x

SomeClass.new_attr = 45
SomeClass.init = init
SomeClass.square = square_method
obj = SomeClass()
obj.init(3)
print(obj.square())                             # 9
print(obj.new_attr)                             # 45


# https://github.com/yt-dlp/yt-dlp
# python3 ./yt-dlp.py
# If target_leaf (see code) does not exist, it will be created.
#
# In wsl/linux, to create a symlink to the usual place...
# 1. ln_target='/mnt/e/Zoolz/C/Videos/YouTube/Others'
# 2. sudo ln -s $ln_target /wintemp
# So... ls -l /wintemp
# lrwxrwxrwx 1 root root 36 Dec 29 16:36 /wintemp -> /mnt/e/Zoolz/C/Videos/YouTube/Others

import datetime
from sys import platform
import os

def download_yt_video():
    ytexe = "./yt-dlp"
    yt_prefix = "https://www.youtube.com/watch?v="

    if (platform == 'linux'):
        SAVE_PATH = "/wintemp"
    else: # assume win32
        raise ValueError

    if not os.path.exists(ytexe):
        # non-checked-in static copy: D:\software\VideoSoftware\YoutubeDownloader\yt-dlp
        raise FileNotFoundError("no file found: [{}]. Exiting...".format(ytexe))

    link = input("Paste the YouTube URL (only the part aafter 'v='): ")
    target_leaf = input(f"What is the folder under {SAVE_PATH} to save the video? (return = none): ")
    output_template = f"{SAVE_PATH}/{target_leaf}/%(title)s-%(id)s"
    command_line = f"{ytexe} -v {yt_prefix}{link} -o '{output_template}'.mp4"
    print(f"[cmd line]: {command_line}")

    os.system(command_line)

    print("Completed download at {}".format(datetime.datetime.now()))
    print("See '[download] Destination' above for output folder and video name")

download_yt_video()


# input: an array of ints
# calculation:
# for even numbers: if negative, each 0 in their binary representation subtracts 1 from evens_score, if positive - adds 1
# for odd numbers: if negative, each 1 subtracts 1, if positive - adds 1 to the odds_score
# output: print the winner team

def calc_scores(p):
    evens_score = 0
    odds_score = 0
    # calls to local functions are less expensive
    lstr = str
    lbin = bin
    for num in p:
        num_binary = lstr(lbin(num))[2:]
        if num % 2 == 0: # even
            if num < 0: # even and negative
                num_binary = num_binary[1:]
                # using map is better than calling int() each time, as it looks up int() only once (and uses C for the call)
                for digit in map(int, num_binary):
                    if digit == 0:
                        evens_score -= 1
            else: # even and positive
                for digit in map(int, num_binary):
                    if digit == 0:
                        evens_score += 1
        else: # odd
            if num < 0: # odd and negative
                num_binary = num_binary[1:]
                for digit in map(int, num_binary):
                    if digit == 1:
                        odds_score -= 1
            else: # odd and positive
                for digit in map(int, num_binary):
                    if digit == 1:
                        odds_score += 1
    return evens_score, odds_score

def battle(p):
    evens_score, odds_score = calc_scores(p)
    if odds_score > evens_score:
        return "odds win"
    elif odds_score < evens_score:
        return "evens win"
    return "tie"


import argparse
import numpy as np
import recova.descriptor.mask

from recova.registration_result_database import RegistrationPairDatabase
from recova.util import eprint
import time

class Descriptor:
    """
    Given a description algorithm and a mask generator, compute a descriptor.

    The mask generator create subset of points on which we compute the description successively.
    For instance a mask generator could be a grid binning algorithm.
    The description algorithm takes a collection of points and outputs a description vector.
    """
    def __init__(self, mask_generator, description_algorithm):
        self.mask_generator = mask_generator
        self.description_algo = description_algorithm

    def __repr__(self):
        return 'descriptor_{}_{}'.format(self.mask_generator.__repr__(),
                                         self.description_algo.__repr__())

    def _compute(self, pair):
        """
        Compute the value of the descriptor for a pointcloud pair.
        """
        reading_masks, reference_masks = self.mask_generator.compute(pair)

        descriptors = []
        for i in range(len(reading_masks)):
            descriptor = self.description_algo.compute(pair, reading_masks[i], reference_masks[i])
            descriptors.append(descriptor)

        flattened_descriptor = []
        for l in descriptors:
            for element in l:
                flattened_descriptor.append(element)

        return np.array(flattened_descriptor)

    def compute(self, pair):
        if repr(self) in pair.cache:
            return pair.cache[repr(self)]
        else:
            descriptor = self._compute(pair)
            pair.cache[repr(self)] = descriptor
            return descriptor

    def labels(self):
        mask_labels = self.mask_generator.labels()
        descriptor_labels = self.description_algo.labels()

        labels = []
        for mask_label in mask_labels:
            for descriptor_label in descriptor_labels:
                labels.append('{}___{}'.format(mask_label, descriptor_label))

        return labels

class DescriptorConcat(Descriptor):
    def __init__(self, descriptors):
        self.descriptors = descriptors

    def __repr__(self):
        desc_reprs = [repr(x) for x in self.descriptors]

        return '_'.join(desc_reprs)

    def labels(self):
        labels = []
        for descriptor in self.descriptors:
            labels.extend(descriptor.labels())

        return labels

    def compute(self, pair):
        descr_concat = []
        for descriptor in self.descriptors:
            descr_concat.extend(descriptor.compute(pair))

        return np.array(descr_concat)


#!/usr/bin/env python

from hashlib import md5

class AdventMiner():

    def __init__(self, secret):
        self.secret = secret

    def get_coin(self, n):
        coin_hash = self.get_hash(n)

        if coin_hash[:5] == "0" * 5:
            return coin_hash
        else:
            return False

    def get_hash(self, n):
        m = md5()
        m.update(self.secret + n)
        return m.hexdigest()

miner = AdventMiner(b"ckczppom")
index = 0
coin = False

while not coin:
    index += 1
    coin = miner.get_coin(str(index).encode())

print(index)


"""
https://leetcode.com/problems/reshape-the-matrix/
"""
class Solution:
    def matrixReshape(self, mat: List[List[int]], r: int, c: int) -> List[List[int]]:
        m, n = len(mat), len(mat[0])
        res = [[0] * c for _ in range(r)]

        if m * n != r * c:
            return mat

        for i in range(m):
            for j in range(n):
                idx = i * n + j
                new_i = idx // c
                new_j = idx % c
                res[new_i][new_j] = mat[i][j]
        return res


from django.shortcuts import redirect
from django.core.exceptions import PermissionDenied
from autoreduce_webapp.uows_client import UOWSClient
from autoreduce_webapp.settings import UOWS_LOGIN_URL, LOGIN_URL, INSTALLED_APPS, USER_ACCESS_CHECKS, OUTDATED_BROWSERS
from autoreduce_webapp.icat_cache import ICATCache
from reduction_viewer.models import ReductionRun, Experiment
from django.template import RequestContext
from django.shortcuts import render
from reduction_viewer.models import Notification, Setting
from settings import DEVELOPMENT_MODE
import logging
logger = logging.getLogger(__name__)

def has_valid_login(request):
    """
    Check that the user is correctly logged in and their session is still considered valid
    """
    logger.debug("Checking if user is authenticated")
    if DEVELOPMENT_MODE:
        logger.debug("DEVELOPMENT_MODE True so allowing access")
        return True
    if request.user.is_authenticated() and 'sessionid' in request.session:
        logger.debug("User is authenticated and has a sessionid from the UOWS")
        return True
    return False

def handle_redirect(request):
    """
    Redirect the user to either capture the session id or to go and log in
    """
    if request.GET.get('sessionid'):
        return redirect(request.build_absolute_uri(LOGIN_URL) + "?next=" + request.build_absolute_uri().replace('?sessionid=', '&sessionid='))
    return redirect(UOWS_LOGIN_URL + request.build_absolute_uri())

def login_and_uows_valid(fn):
    """
    Function decorator to check whether the user's session is still valid
    """
    def request_processor(request, *args, **kws):
        if has_valid_login(request):
            return fn(request, *args, **kws)
        return handle_redirect(request)
    return request_processor

def require_staff(fn):
    """
    Function decorator to check whether the user is a staff memeber
    """
    def request_processor(request, *args, **kws):
        if has_valid_login(request):
            if request.user.is_staff:
                return fn(request, *args, **kws)
            else:
                raise PermissionDenied()
        else:
            return handle_redirect(request)
    return request_processor

def require_admin(fn):
    """
    Function decorator to check whether the user is a superuser
    """
    def request_processor(request, *args, **kws):
        if has_valid_login(request):
            if request.user.is_superuser:
                return fn(request, *args, **kws)
            else:
                raise PermissionDenied()
        else:
            return handle_redirect(request)
    return request_processor

def render_with(template):
    """
    Decorator for Django views that sends returned dict to render function
    with given template and RequestContext as context instance.
    """
    def renderer(fn):
        def populate_template_dict(request, output):
            if 'request' not in output:
                output['request'] = request

            notifications = Notification.objects.filter(is_active=True, is_staff_only=(request.user.is_authenticated() and request.user.is_staff))
            if 'notifications' not in output:
                output['notifications'] = notifications
            else:
                output['notifications'].extend(notifications)

            if 'bad_browsers' not in output:
                # Load in the list of not accepted browsers from the settings
                bad_browsers = []
                for browser in OUTDATED_BROWSERS:
                    bad_browsers.append((browser, OUTDATED_BROWSERS[browser]))

                # Get the family and version from the user_agent
                family = request.user_agent.browser.family
                version = request.user_agent.browser.version_string

                # Make sure we are only comparing against a single integer
                if '.' in version:
                    version = int(version[0:(version.index('.'))])
                else:
                    version = int(version)

                # Check whether the browser is outdated
                outdated = False
                for browser in bad_browsers:
                    if browser[0] == family and version <= browser[1]:
                        outdated = True

                # Change to more user-friendly language
                if family == "IE":
                    family = "Microsoft Internet Explorer"

                output['bad_browsers'] = bad_browsers
                output['current_browser'] = family
                output['version'] = version
                output['outdated'] = outdated

            if 'reduction_variables_on' not in output:
                output['reduction_variables_on'] = ('reduction_variables' in INSTALLED_APPS)

            if 'support_email' not in output:
                support_email = Setting.objects.filter(name='support_email').first()
                if support_email:
                    output['support_email'] = support_email.value

            return output

        def wrapper(request, *args, **kw):
            output = fn(request, *args, **kw)
            if isinstance(output, dict):
                output = populate_template_dict(request, output)
                return render(request, template, output)
            return output
        return wrapper
    return renderer

def check_permissions(fn):
    """
    Checks that the user has permission to access the given experiment and/or instrument.
    Queries ICATCache to check owned instruments and experiments.
    """
    def request_processor(request, *args, **kwargs):
        if USER_ACCESS_CHECKS and not request.user.is_superuser:
            # Get the things to check by from the arguments supplied.
            experiment_reference, owned_instrument_name, viewed_instrument_name, optional_instrument_names = None, None, None, []
            if "run_number" in kwargs:
                # Get the experiment and instrument from the given run number.
                run = ReductionRun.objects.filter(run_number=int(kwargs["run_number"])).first()
                experiment_reference, viewed_instrument_name = run.experiment.reference_number, run.instrument.name
            else:
                # Get the experiment reference if it's supplied.
                if "reference_number" in kwargs:
                    experiment_reference = int(kwargs["reference_number"])
                    # Find the associated instrument.
                    experiment_obj = Experiment.objects.filter(reference_number=experiment_reference).first()
                    if experiment_obj:
                        optional_instrument_names = list(set([run.instrument.name for run in experiment_obj.reduction_runs.all()]))
                else:
                    # Look for an instrument name under 'instrument_name', or, failing that, 'instrument'.
                    owned_instrument_name = kwargs.get("instrument_name", kwargs.get("instrument"))

            with ICATCache(AUTH='uows', SESSION={'sessionid':request.session['sessionid']}) as icat:
                owned_instrument_list, valid_instrument_list = icat.get_owned_instruments(int(request.user.username)), icat.get_valid_instruments(int(request.user.username))

                # Check for access to the instrument
                if owned_instrument_name or viewed_instrument_name:
                    optional_instrument_names.append(owned_instrument_name if owned_instrument_name is not None else viewed_instrument_name)

                    # Check access to an owned instrument.
                    if owned_instrument_name is not None and owned_instrument_name not in owned_instrument_list:
                        raise PermissionDenied() # No access allowed

                    # Check access to a valid instrument (able to view some runs, etc.).
                    if viewed_instrument_name is not None and viewed_instrument_name not in owned_instrument_list + valid_instrument_list:
                        raise PermissionDenied() # No access allowed

                # Check for access to the experiment; if the user owns one of the associated instruments, we don't need to check this.
                if optional_instrument_names and list(set(optional_instrument_names).intersection(owned_instrument_list)):
                    pass
                elif experiment_reference is not None and experiment_reference not in icat.get_associated_experiments(int(request.user.username)):
                    raise PermissionDenied()

        # If we're here, the access checks have passed.
        return fn(request, *args, **kwargs)

    return request_processor


# https://github.com/agdelma/IntroCompPhysics/blob/master/Notebooks/26_Quadrature.ipynb

import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from scipy.constants import pi as π

colors = ["#2078B5", "#FF7F0F", "#2CA12C", "#D72827", "#9467BE", "#8C574B",
          "#E478C2", "#808080", "#BCBE20", "#17BED0", "#AEC8E9", "#FFBC79",
          "#98E08B", "#FF9896", "#C6B1D6", "#C59D94", "#F8B7D3", "#C8C8C8",
          "#DCDC8E", "#9EDAE6"]

def dBx(t,x,y,z,ω):
    '''x-component of the B field (in units of μ0I)'''
    r = (x-np.cos(ω*t))**2+(y-t)**2+(z-np.sin(ω*t))**2
    return (1/(4.0*π))*(z - np.sin(ω*t) - ω*np.cos(ω*t)*(y-t))/r**3/2

def dBy(t,x,y,z,ω):
    '''y-component of the B field (in units of μ0I)'''
    r = (x-np.cos(ω*t))**2+(y-t)**2+(z-np.sin(ω*t))**2
    return (1/(4.0*π))*(ω*np.sin(ω*t)*(z-np.sin(ω*t))+ω*np.cos(ω*t)*(x-np.cos(ω*t)))/r**3/2

def dBz(t,x,y,z,ω):
    '''z-component of the B field (in units of μ0I)'''
    r = (x-np.cos(ω*t))**2+(y-t)**2+(z-np.sin(ω*t))**2
    return (1/(4.0*π))*(-ω*np.sin(ω*t)*(y-t)-x+np.cos(ω*t))/r**3/2

def trapezoidal_rule(f,x,*params):
    '''The trapezoidal rule for numerical integration of f(x) over x.'''

    a,b = x[0],x[-1]
    Δx = x[1] - x[0]
    np.delete(x, 0)
    np.delete(x, -1)

    ###
    I = (Δx/2) * (f(a, *params) + f(b, *params)) + np.sum(f(x, *params) * Δx)
    ###

    return I

N = 500
t = np.linspace(-4*π,4*π,N)

ω = 15

# along the axis
y = np.linspace(-20,20,N)
x,z = 0,0

Bx = np.zeros_like(y)
By = np.zeros_like(y)
Bz = np.zeros_like(y)

for i in range(N):
    Bx[i] = trapezoidal_rule(dBx,t,x,y[i],z,ω)
    By[i] = trapezoidal_rule(dBy,t,x,y[i],z,ω)
    Bz[i] = trapezoidal_rule(dBz,t,x,y[i],z,ω)

plt.plot(y,Bx,label=r'$B_x(0,y,0)$')
plt.plot(y,By, label=r'$B_y(0,y,0)$')
plt.plot(y,Bz, label=r'$B_z(0,y,0)$')

plt.legend(frameon=True, loc='lower right')
plt.xlabel('y')
plt.ylabel(r'$B/\mu_0 I$')

plt.show()


# -*- coding: utf-8 -*-
from django.shortcuts import render
from django.http import HttpResponse
from .models import Fphoto
from .forms import FphotoForm

def index(request):
    photos = Fphoto.objects.all()
    form = FphotoForm()
    context = {
        'photos': photos,
        'form': form
    }
    return render(request, 'finger/index.html', context)

def add_finger(request):
    form = FphotoForm()
    if request.method == 'POST':
        form = FphotoForm(request.POST, request.FILES)
        if form.is_valid():
            if 'photo' in request.FILES:
                form.photo = request.FILES['photo']
            form.save(commit=True)
            arr_photos = Fphoto.objects.all().order_by('-id')[0]
            print(arr_photos.img_1.path)
            print(arr_photos.img_2.path)
            result = checkFinger(arr_photos.img_1.path, arr_photos.img_2.path)
            print(result)

            arr_photos.num_evd = result
            arr_photos.save()
            if result > 80:
                context = {
                    'photos': arr_photos,
                    'num': result
                }
                return render(request, 'finger/result.html', context)
            else:
                return HttpResponse("Не прошел")
        else:
            print(form.errors)
        return render(request, 'finger/index.html', {'form': form})
    else:
        return HttpResponse('no')

from tkinter import *
from PIL import Image
import finger.lib.templateSkeletize2 as sk

def binary(img):
    bImg = []
    for i in range(img.size[0]):
        tmp = []
        for j in range(img.size[1]):
            t = img.getpixel((i, j))
            p = t[0] * 0.3 + t[1] * 0.59 + t[2] * 0.11
            if p > 128:
                p = 1
            else:
                p = 0
            tmp.append(p)
        bImg.append(tmp)
    return bImg

def __removeDouble(x, y):
    z = []
    for i in x:
        c = True
        for j in y:
            if i == j:
                c = False
        if c:
            z.append(i)
    for i in y:
        c = True
        for j in x:
            if i == j:
                c = False
        if c:
            z.append(i)
    return z

def delNoisePoint(r):
    tmp = []
    tmp2 = []
    for i in r[1]:
        x = range(i[0] - 5, i[0] + 5)
        y = range(i[1] - 5, i[1] + 5)
        for j in r[0]:
            if j[0] in x and j[1] in y:
                tmp.append(i)
                tmp2.append(j)
    return (__removeDouble(r[0], tmp2), __removeDouble(r[1], tmp))

def matchingPoint(r, v):
    all = 0
    match = 0
    for i in v[0]:
        x = range(i[0] - 15, i[0] + 15)
        y = range(i[1] - 15, i[1] + 15)
        all += 1
        for j in r[0]:
            if j[0] in x and j[1] in y:
                match += 1
                break
    for i in v[1]:
        x = range(i[0] - 15, i[0] + 15)
        y = range(i[1] - 15, i[1] + 15)
        all += 1
        for j in r[1]:
            if j[0] in x and j[1] in y:
                match += 1
                break

    return (match, all)

def checkThisPoint(img, x, y):
    c = 0
    for i in range(x - 1, x + 2):
        for j in range(y - 1, y + 2):
            if img[i][j] == 0:
                c += 1
    return c - 1

def findCheckPoint(img):
    x = len(img)
    y = len(img[0])
    branchPoint = []
    endPoint = []
    for i in range(x):
        for j in range(y):
            if img[i][j] == 0:
                t = checkThisPoint(img, i, j)
                if t == 1:
                    endPoint.append((i, j))
                if t == 3:
                    branchPoint.append((i, j))
    return (branchPoint, endPoint)

def checkFinger(r, v):
    reference = Image.open(r)

    ref = binary(reference)

    sk.tmpDelete(ref)
    rp = findCheckPoint(ref)
    rp = delNoisePoint(rp)

    verf = Image.open(v)

    ver = binary(verf)

    sk.tmpDelete(ver)
    vp = findCheckPoint(ver)
    vp = delNoisePoint(vp)

    res = matchingPoint(rp, vp)
    r = (res[0] / (res[1] * 1.)) * 100

    # root = Tk()
    # w = len(ver)
    # h = len(ver[0])
    # C = Canvas(root, width=w * 2, height=h)
    #
    # for i in range(w):
    #     for j in range(h):
    #         if ref[i][j] == 0:
    #             C.create_line([(i, j), (i + 1, j + 1)])
    #         if ver[i][j] == 0:
    #             C.create_line([(i + w + 1, j + 1), (i + w, j)])
    # for i in rp[0]:
    #     C.create_oval([(i[0] - 3, i[1] - 3), (i[0] + 3, i[1] + 3)], outline="#ff0000")
    # for i in rp[1]:
    #     C.create_rectangle([(i[0] - 3, i[1] - 3), (i[0] + 3, i[1] + 3)], outline="#0000ff")
    # for i in vp[0]:
    #     C.create_oval([(i[0] - 3 + w, i[1] - 3), (i[0] + 3 + w, i[1] + 3)], outline="#ff0000")
    # for i in vp[1]:
    #     C.create_rectangle([(i[0] - 3 + w, i[1] - 3), (i[0] + 3 + w, i[1] + 3)], outline="#0000ff")
    #
    # C.create_text((w, h * 0.95), fill="#009900", text=str(r) + "%", font='Arial,72')
    #
    # C.pack()
    # root.mainloop()
    return r


import networkx as nx
import numpy as np
import os
import math
import matplotlib.pyplot as plt
import getEdgePair
from lxml import etree
from scipy import optimize
from getNet import get_nx, divide_name, get_mat
from getEdgeTime import get_all_edge_time
from finePlot import plot
from getFeatureJudge import get_k_shell_dict
from __Configuration import *

def show_info_with_net(_net_name):
    """
    展示网络的边数，节点数，聚类系数，直径
    :param _net_name:
    :return:
    """
    with open(".\\net_data\\meta_info.txt", 'a') as net_data_info:
        net = get_nx(_net_name)
        node_num = net.number_of_nodes()
        edge_num = net.number_of_edges()
        print("NET:", _net_name, " Num of edges:", edge_num, " Num of nodes:", node_num)
        net_data_info.write("NET:" + _net_name + " Num of edges:" + str(edge_num) + " Num of nodes:" +
                            str(node_num) + '\n')

        # cluster_coefficient = nx.average_clustering(net)
        # print("Cluster Coefficient:", cluster_coefficient)
        # net_data_info.write("Cluster Coefficient:" + str(cluster_coefficient) + '\n')
        #
        # max_diameter = 0
        # for sub_net in nx.connected_component_subgraphs(net):
        #     diameter = nx.diameter(sub_net)
        #     if diameter > max_diameter:
        #         max_diameter = diameter
        # print("Diameter:", max_diameter)
        # net_data_info.write("Diameter:" + str(max_diameter) + '\n')
        # 获取网络能区分新旧的边对数
        edges_num_with_day = show_edge_nums_with_time(_net_name)
        day_num = len(edges_num_with_day)
        ep_num = 0
        for i in range(day_num):
            for j in range(i, day_num):
                if i != j:
                    ep_num += edges_num_with_day[i] * edges_num_with_day[j]
        # ep_num = 0
        # for edge_pair, new in getEdgePair.get_all_edge_pairs(_net_name):
        #     ep_num += 1
        print("different time edge_pair num: ", ep_num)
        net_data_info.write("different time edge_pair num: " + str(ep_num) + '\n')
        print("-----------------slice line-----------------")
        net_data_info.write("-----------------slice line-----------------" + '\n')

def show_edge_nums_with_time(_net_name):
    """
    展示网络不同时间边的数量
    :param _net_name:
    :return:
    """
    edge_days = get_all_edge_time(_net_name)
    days = sorted(set(edge_days.values()))
    edges_num_with_day = [0] * len(days)
    for edge in edge_days.keys():
        edges_num_with_day[days.index(edge_days[edge])] += 1
    plt.figure(figsize=(10, 5))
    plot(range(len(days)), edges_num_with_day, 'day', 'edges', _net_name + ' Edges in days', None)
    plt.savefig(".\\net_data\\" + str(divide_name(_net_name)[0]) + "\\edge_num_with_time.png", dpi=600)
    plt.show()
    return edges_num_with_day

def line(x, a, b):
    return a * x + b

def show_degree_dis_with_net(_net_name):
    """
    展示网络的度分布，使用双对数坐标系
    :param _net_name:
    :return:
    """
    net = get_nx(_net_name)
    degree_dis = nx.degree_histogram(net)
    x = []
    y = []
    for degree in range(1, len(degree_dis)):  # 排除孤立节点
        if degree_dis[degree] != 0:
            x.append(math.log2(degree))
            y.append(math.log2(degree_dis[degree] / float(sum(degree_dis))))
    # 拟合
    a, b = optimize.curve_fit(line, x, y)[0]
    x1 = np.arange(0, max(x), 0.01)
    y1 = a * x1 + b

    plt.figure(figsize=(10, 5))
    plt.title(_net_name + ' Degree distribution, k is ' + str(round(a, 3)), fontsize=25, fontweight='bold')
    plt.xlabel('log(degree)', fontsize=15, fontweight='bold')
    plt.ylabel('log(degree dis)', fontsize=15, fontweight='bold')
    plt.scatter(x, y, color='blue', linewidth=2)

    plt.plot(x1, y1, "r")
    plt.savefig(".\\net_data\\" + str(divide_name(_net_name)[0]) + "\\last_graph_degree_dis.png", dpi=600)
    plt.show()

def show_k_shell_dis_with_net(_net_name):
    """
    展示网络的边的k_shell分布
    :param _net_name:
    :return:
    """
    k_shell_dict = get_k_shell_dict(get_mat(_net_name), _net_name)
    max_k_shell = int(max(k_shell_dict.values()))
    x = list(range(1, max_k_shell+1))
    dis = np.zeros(max_k_shell)
    for edge in k_shell_dict:
        dis[int(k_shell_dict[edge]) - 1] += 1
    plt.figure(figsize=(10, 5))
    plt.title(_net_name + ' k_shell distribution', fontsize=25, fontweight='bold')
    plt.xlabel('k_shell', fontsize=15, fontweight='bold')
    plt.ylabel('p', fontsize=15, fontweight='bold')
    plt.bar(x, dis, color='blue', linewidth=2)
    plt.show()

def write_to_gephi(_net_name):
    """
    将网络转换维gexf文件，方便gephi使用
    :param _net_name:
    :return:
    """
    net_type, net_time = divide_name(_net_name)
    net = get_nx(_net_name)
    if os.path.exists(".\\net_data\\" + net_type + "\\gephi\\") is False:
        os.mkdir(".\\net_data\\" + net_type + "\\gephi\\")
    if net_time != "":
        file_name = ".\\net_data\\" + net_type + "\\gephi\\" + str(net_time) + ".gexf"
    else:
        file_name = ".\\net_data\\" + net_type + "\\gephi\\" + str(net_type) + ".gexf"
    nx.write_gexf(net, file_name)

def plot_graph(_net_name):
    net_type, net_time = divide_name(_net_name)
    path = ".\\net_data\\" + net_type + "\\gephi\\" + net_type + '_' + str(net_time) + "_dynamic.gexf"
    edge_days = get_all_edge_time(_net_name)
    days = sorted(set(edge_days.values()))
    start_day = days[0]
    end_day = days[-1]
    # xml 编写
    nsmap = {'xsi': 'http://www.w3.org/2001/XMLSchema-instance'}
    gexf = etree.Element('gexf', nsmap=nsmap)
    gexf.set('xmlns', 'http://www.gexf.net/1.1draft')
    gexf.set('version', '1.1')

    graph = etree.SubElement(gexf, 'graph', attrib={'mode': 'dynamic', 'defaultedgetype': 'undirected'})
    nodes = etree.SubElement(graph, 'nodes')
    edges = etree.SubElement(graph, 'edges')
    node_list = []
    for edge_day in edge_days.keys():
        if edge_day[0] not in node_list:
            node_list.append(edge_day[0])
            xml_node = etree.Element('node', attrib={'id': str(edge_day[0]), 'label': str(edge_day[0]),
                                                     'start': str(start_day), 'end': str(end_day)})
            nodes.append(xml_node)
        if edge_day[1] not in node_list:
            node_list.append(edge_day[1])
            xml_node = etree.Element('node', attrib={'id': str(edge_day[1]), 'label': str(edge_day[1]),
                                                     'start': str(start_day), 'end': str(end_day)})
            nodes.append(xml_node)
        xml_edge = etree.Element('edge', attrib={'source': str(edge_day[0]), 'target': str(edge_day[1]),
                                                 'start': str(edge_days[edge_day])})
        edges.append(xml_edge)
    gexf_tree = etree.ElementTree(gexf)
    gexf_tree.write(path, pretty_print=True, xml_declaration=True, encoding='utf-8')

if __name__ == '__main__':
    net_names = protein_net_names  # social_net_names[2:]  # protein_net_names + ["sci_net_contacts%51"]
    for net_name in net_names:
        show_degree_dis_with_net(net_name)
        # show_edge_nums_with_time(net_name)
        # write_to_gephi(net_name)
        # plot_graph(net_name)
        # show_k_shell_dis_with_net(net_name)
        # show_info_with_net(net_name)
        pass


#!/usr/bin/env python3
# -*- coding:utf-8 -*-
'''
画图
1.坐标轴设置
2.改变坐标轴的方式

'''

__author__ = 'Jackie Qiang'

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-1, 1, 50)
y1 = 2*x +1
y2 = x**2

plt.figure()
plt.plot(x, y2)
plt.plot(x, y1, color='red', linewidth=1.0, linestyle='--')

plt.xlim((-1, 2))    #x轴的取值范围
plt.ylim((-2,3))    #y轴的取值范围
plt.xlabel('a\sdf')
plt.ylabel('i am y')

new_ticks = np.linspace(-1, 2, 5)
print(new_ticks)
plt.xticks(new_ticks)   #修改角标，范围从-1到2.共有5个点
plt.yticks([-2, -1.8, -1, 1.22, 3,],
    [r'$really\ bad$', r'$bad\ \alpha$', 'normal', 'good', 'really good']) #修改y轴的角标

#gca = 'get current axis'
ax =plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
ax.spines['bottom'].set_position(('data', 0)) # outward, axis
ax.spines['left'].set_position(('data', 0))

plt.show()


import tensorflow as tf
from tensorflow.contrib import slim
import sonnet as snt

__all__ = ['LayerNormalization', 'SpatialDropout', 'CausalConv2D']

class LayerNormalization(snt.AbstractModule):
    def __init__(self,
                 eps=1e-5,
                 initializers=None,
                 partitioners=None,
                 regularizers=None,
                 name="layer_normalization"):
        super(LayerNormalization, self).__init__(name=name)
        with self._enter_variable_scope():
            self._layer_norm = snt.LayerNorm(eps=eps,
                                             initializers=initializers,
                                             partitioners=partitioners,
                                             regularizers=regularizers,
                                             name=f'{name}_core')

    def _build(self, inputs):
        """Connects the LayerNorm module into the graph.

        Args:
            inputs: a Tensor of shape `[batch_size, ..., layer_dim]`.

        Returns:
            normalized: layer normalized outputs with same shape as inputs.
        """

        inputs_shape = inputs.get_shape().as_list()
        hidden_size = inputs_shape[-1]
        reshaped_inputs = tf.reshape(inputs, shape=[-1, hidden_size])
        reshaped_normalized = self._layer_norm(reshaped_inputs)
        normalized = tf.reshape(reshaped_normalized, shape=[-1] + inputs_shape[1:])
        return normalized

class SpatialDropout(snt.AbstractModule):
    def __init__(self,
                 keep_prob,
                 name='spatial_dropout'):
        super(SpatialDropout, self).__init__(name=name)
        self._keep_prob = keep_prob

    def _build(self, x, is_training):
        x_shape = tf.shape(x)
        noise_shape = [x_shape[0]] + [1] * (len(x.get_shape()) - 2) + [x_shape[-1]]
        result = slim.dropout(x, self._keep_prob, noise_shape=noise_shape, is_training=is_training)
        return result

class CausalConv2D(snt.AbstractModule):
    def __init__(self, output_channels, kernel_shape, stride=1, rate=1,
                 use_bias=True, initializers=None,
                 partitioners=None, regularizers=None, mask=None,
                 data_format="NHWC", custom_getter=None,
                 name="causal_conv_2d"):
        super(CausalConv2D, self).__init__(name=name)
        with self._enter_variable_scope():
            self._conv = snt.Conv2D(output_channels, kernel_shape, stride, rate,
                                    'VALID', use_bias, initializers, partitioners, regularizers,
                                    mask, data_format, custom_getter)

    def _build(self, inputs):
        kernel_shape = self._conv.kernel_shape
        rate = self._conv.rate
        pad_amount_0 = int((kernel_shape[0] - 1) * rate[0])
        pad_amount_1 = int((kernel_shape[1] - 1) * rate[1])
        padded_inputs = tf.pad(inputs, paddings=[[0, 0], [pad_amount_0, 0], [pad_amount_1, 0], [0, 0]])
        return self._conv(padded_inputs)


class ListView(Frame):
    def __init__(self, screen, model):
        super(ListView, self).__init__(screen,
                                       screen.height * 2 // 3,
                                       screen.width * 2 // 3,
                                       on_load=self._reload_list,
                                       hover_focus=True,
                                       title="Courses")
        # Save off the model that accesses the contacts database.
        self._model = model

        # Create the form for displaying the list of contacts.
        self._list_view = ListBox(
            Widget.FILL_FRAME,
            model.get_summary(),
            name="contacts",
            on_change=self._on_pick)
        self._edit_button = Button("Edit", self._edit)
        self._delete_button = Button("Delete", self._delete)
        layout = Layout([100], fill_frame=True)
        self.add_layout(layout)
        layout.add_widget(self._list_view)
        layout.add_widget(Divider())
        layout2 = Layout([1, 1, 1, 1])
        self.add_layout(layout2)
        layout2.add_widget(Button("Add", self._add), 0)
        layout2.add_widget(self._edit_button, 1)
        layout2.add_widget(self._delete_button, 2)
        layout2.add_widget(Button("Quit", self._quit), 3)
        self.fix()


import socket
import sys

# https://www.bogotobogo.com/python/python_network_programming_server_client.php

# creates socket object
s = socket.socket(socket.AF_INET,
                  socket.SOCK_STREAM)

# host = socket.gethostname() # or just use (host = '')
host = 'localhost'
port = 9999

print (host)
print (port)
# sys.exit(1)

s.connect((host, port))

tm = s.recv(1024) # msg can only be 1024 bytes long

s.close()
print("the time we got from the server is %s" % tm.decode('ascii'))


from geometor import Geometor

class Graphics_Geometor(Geometor):
    def originize_point(self, point):
        """Converts graphics representation to standard
        and then calculates point relative to origin

        Arguments:
            point: length 2 tuple to convert

        Returns point relative to origin """

        self._tuple_is_usable(point)

#       Make points relative to origin
        x_r_point = point[0] - self.origin[0]

        #In graphics, the object is REVERSED
        y_r_point =  self.origin[1] - point[1]
        r_point = (x_r_point, y_r_point)
        return r_point


from math import atan2, degrees, sqrt
def getDeg(u, v):
    deg = degrees(atan2(v[1] - u[1], v[0] - u[0])) + 360
    return deg if deg >= 270 else 360 + deg

def getMag(u, v): return sqrt((v[0] - u[0])**2 + (v[1] - u[1])**2)

space = list(map(lambda x: x.strip(), open('input').readlines()))
# space = list(map(lambda x: x.strip(), open('inb').readlines()))

astes = []

for y in range(len(space)):
    for x in range(len(space[0])):
        aste = space[y][x]
        if aste == '#': astes.append((x,y))

counter = 0

for center in astes:
    detected = set(getDeg(center, aste) for aste in astes)
    if counter < len(detected):
        counter = len(detected)
        target = center
print('Part 1:', counter, target)

asteroids = {}
for aste in astes:
    d = getDeg(target,aste)
    if aste == (11, 12) or aste == (11,14): print(aste, d, d % 360)
    asteroids.setdefault(d, []).append({
        'mag': getMag(target,aste),
        'pos': aste
    })
    asteroids[d] = list(sorted(asteroids[d], key = lambda x: x['mag']))

counter = 0
while True:
    for deg in sorted(asteroids):
        if len(asteroids[deg]) > 0:
            asteroid = asteroids[deg].pop(0)
            counter += 1
            print(f'{counter} vaporized at {asteroid["pos"]}')
            if counter == 200:
                pos = asteroid['pos']
                exit(pos, pos[0]*100 + pos[1])
                exit()