from ACaS import *
import os
import pickle
import random
import time

sf = "saves/" #save folder!
asset_folder = "ISG_assets/"
os.system("pip install -r requirements.txt")
import pygame
class troop(object):

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

    def attack(self, attack):
        self.attack = attack

    def health(self, hp):
        self.hp = hp

class pygameControl(object):

    def __init__(self, sizeX, sizeY):
        pygame.init()
        self.display = pygame.display.set_mode((sizeX, sizeY))
        self.clock = pygame.time.Clock()
        pygame.display.set_caption('--Unnamed--')
        self.sizeX = sizeX
        self.sizeY = sizeY

    def title(self, title):
        pygame.display.set_caption(title)

    def BlitIt(self, x, y, image):
        self.display.blit(image, (x, y))

    def BlackOut(self):
        self.display.fill((0,0,0))

"""

a fun gap!!!

"""

class level(object):

    def __init__(self, sizeY, sizeX):
        self.xmap = []
        self.ymap = []
        for count in range(sizeY):
            self.ymap.append("O")
        for count in range(sizeX):
            self.xmap.append("O")
        self.xPlayer = 0
        self.yPlayer = 0
        self.xCordrom = []
        self.yCordrom = []
        self.sizeCordrom = [] #Cord word does nothing it just sorta makes it seem part of the y and x Cordrom variables

    #def image(self, location):
        #self.image = pygame.image.load(asset_folder + location)

    def imageScaler(self, scale, x, y):
        self.image = pygame.transform.scale(self.image, (int(x*scale) , int(y*scale)))
        self.imageXsize = int(x*scale)
        self.imageYsize = int(y*scale)

    def change_layout(self, sizeY, sizeX):
        self.xmap = []
        self.ymap = []
        for count in range(sizeY):
            self.ymap.append("O")
        for count in range(sizeX):
            self.xmap.append("O")

    def player_on(self, locx, locy):
        self.xmap[locx] = "X"
        self.ymap[locy] = "X"

"""
    def move_player(self):
        if (self.ymap[0] = "X") and (self.xmap[len(self.xmap)//2]):
            self.yPlayer += 1
            #update player cords
            #make new room details
            #generate new room
"""

class monster(object):

    def __init__(self, name, health, attack_power):
        self.name = name
        self.hp = health
        self.attack = attack_power

    def level_effector(self, level, ammount_increase):
        ammount_increase += 1
        level -= 1
        for count in range(level):
            self.hp *= ammount_increase
            self.attack *= ammount_increase
            self.attack = int(self.attack)
            self.hp = int(self.hp)

    def defense(self, defense):
        self.defense = defence

    def type(self, type):
        self.type = type

    def image(self, location):
        self.image = pygame.image.load(asset_folder + location)

    def imageScaler(self, scale, x, y):
        self.image = pygame.transform.scale(self.image, (int(x*scale) , int(y*scale)))
        self.imageXsize = int(x*scale)
        self.imageYsize = int(y*scale)

class player(object):

    def __init__(self):
        self.directionPoint = 1
        self.directionList = ["backright.png", "frontright.png", "frontleft.png", "backleft.png"]
        self.moved = False

    def attack(self, attack):
        self.attack = attack

    def name(self, name):
        self.name = name

    def hp(self, hp):
        self.hp = hp

    def mp(self, mp):
        self.mp = mp

    def age(self, age):
        self.age = age

    def levelsetup(self):
        self.level = 1

    def level_adaptor(self):
        self.previousLevel = self.level
        self.level = 0
        for count in range(0, len(self.level_adv)):
            if self.xp >= self.level_adv[count]:
                self.level = count + 1
        self.level += 1

        if self.previousLevel != self.level:
            self.hp = 100 * self.level
            self.attack = 5 * self.level
            print(self.previousLevel)
            print(self.level)
            global occorunce
            occorunce = True

    def xp(self, xp):
        self.xp = xp

    def image(self, location):
        self.image = pygame.image.load(asset_folder + location)

    def level_advancement(self, max_level, incline, start_point):
        self.level_adv = []
        xp_climb = start_point
        for count in range(max_level):
            self.level_adv.append(int(xp_climb))
            xp_climb *= 1 + incline

    def defense(self, defense):
        self.defense = defense

    def type(self, type):
        self.type = type

    def imageScaler(self, scale, x, y):
        self.image = pygame.transform.scale(self.image, (int(x*scale) , int(y*scale)))
        self.imageXsize = int(x*scale)
        self.imageYsize = int(y*scale)

    def existance(self, x, y):
        self.x = x
        self.y = y

    def direction(self, angle):
        self.directionPoint += 1*angle
        if self.directionPoint == 4:
            self.directionPoint = 0
        elif self.directionPoint == -1:
            self.directionPoint = 3
        self.image = pygame.image.load(asset_folder + self.directionList[self.directionPoint])
        self.moved = True

    def move_forward(self): #the elses and passes makes it clean but are uselesss
        if self.directionPoint == 0:
            if dungeon.ymap[0] != "X":
                self.y -= 1
                self.moved = True
            else:
                pass
        elif self.directionPoint == 1:
            if dungeon.xmap[len(dungeon.xmap)-1] != "X":
                self.x += 1
                self.moved = True
            else:
                pass
        elif self.directionPoint == 2:
            if dungeon.ymap[len(dungeon.ymap)-1] != "X":
                self.y += 1
                self.moved = True
            else:
                pass
        elif self.directionPoint == 3:
            if dungeon.xmap[0] != "X":
                self.x -=1
                self.moved = True
            else:
                pass
        if self.moved == True:
            self.eventBegin = random.randint(1, 100)
            if self.eventBegin >= 90:
                self.scenePrep = "Battle"
            else:
                self.scenePrep = "Tileset"

class event_manager(object):

    def type_advantige(self):
        self.adv = {}

    def advantige_check(self, AType, DType):
        if DType in battle.adv[AType]:
            return True
        else:
            return False

    def running(self, running):
        if running == "on":
            self.running = True
        elif running == "off":
            self.running = False

def clicked():
    clickedSund = pygame.mixer.Sound(asset_folder + "clickity.ogg")
    clickedSund.play()

enemies = {
"enemy1" : ["Slime", 30, 2, 8, "slime.png", 346, 249, 225, 50, 0.9], #name, hp, attack, xp, image name, rescale x, rescale y, x location, y location, scale
"enemy2" : ["Wolf", 60, 5, 16, "wolf.png", 413, 390, 225, 50, 0.8],
"enemy3" : ["Ogre", 120, 15, 32, "ogre.png", 310, 390, 225, 30, 0.8]
}

possipleWepons = {
"Wepon1" : ["A basic sword made form cheap steel.", "Basic Sword", "Attack", 2],
"Wepon2" : ["A cane carved from a health tree.", "Cane of Life", "HP", 25],
"Wepon3" : ["A simple axe used for cutting trees", "Tree Cutter Axe", "Attack", 4],
"Wepon4" : ["Creak, aim, SNIPE!", "Wooden Bow and Arrow", "Attack", 3],
"Wepon5" : ["Whack! Smash 'der head in!'", "Mallace", "Attack", 6],
"Wepon6" : ["The trick to dent armor is a ball that can smash.", "Ball and Chain", "Attack", 5],
"Wepon7" : ["Like a Mallace but looks better.", "War Hammer", "Attack", 7]
}

pygame.mixer.pre_init(44100, -16, 1, 512)
pygame.mixer.init()
pygame.mixer.music.set_volume(0)

oof = pygameControl(800, 600) #size of the screen
oof.title("Isometric Dungeon Crawler") #name of the screen

"""
monster = enemy("Dragon", 10, 4)
monster.level_effector(3, 0.4)
monster.type("Poison")
"""

"""
advant = {"Fire": ["Grass", "Tree", "Ice", "Poison"]}
"""
battle = event_manager() #runs battle events
"""
battle.type_advantige()
battle.adv = advant
print(battle.advantige_check(myplayer.type, monster.type))
"""

pygame.mixer.music.load(asset_folder + "dungeonTheme.ogg")

occorunce = False

captureX = 0
captureY = 0

saveImg = pygame.image.load(asset_folder + "saveImg.png")

click = 0
print("START!!!")
downKey = False
work = False #doenst seem to be used... hmmmm!!!!!! *loud hmm*
battle.running("on")
scene = "Menu"
BackgroundImg =  pygame.image.load(asset_folder + "menuDungeon.png")
startImg = pygame.image.load(asset_folder + "newgame.png")
continueImg = pygame.image.load(asset_folder + "continue.png")
soundImg = pygame.image.load(asset_folder + "sound.png")
soundImg = pygame.transform.scale(soundImg, (456//3, 390//3))
Sscale = 1
startImg = pygame.transform.scale(startImg, (int(362*Sscale) , int(76*Sscale)))
startImg = pygame.transform.scale(startImg, (int(306*Sscale) , int(78*Sscale)))

menuImg = pygame.image.load(asset_folder + "menu.png")
#menuImg = pygame.transform.scale(menuImg, (int())) #work here ----------------

itemDirectory = 1

musicUndergo = False

HaCimg = pygame.image.load(asset_folder + "HaC.png")
soundOn = -1
pygame.font.init()
itemDescription = False
myfont = pygame.font.Font("ARDARLING.ttf", 30)
while battle.running:

    if scene == "Menu":
        if musicUndergo == False:
            pygame.mixer.music.stop()
            pygame.mixer.music.play(-1)
            musicUndergo = True
        battleUndergo = False
        oof.BlitIt(0, 0, BackgroundImg)
        oof.BlitIt(400-362*Sscale//2, 100, startImg)
        oof.BlitIt(400-306*Sscale//2, 200, continueImg)
        oof.BlitIt(400-512*Sscale//2, 300, HaCimg)
        if soundOn == 1:
            soundImg = pygame.image.load(asset_folder + "sound.png")
        elif soundOn == -1:
            soundImg = pygame.image.load(asset_folder + "soundoof.png")
        soundImg = pygame.transform.scale(soundImg, (456//3, 390//3))
        oof.BlitIt(800-456//3, 600-390//3, soundImg)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                battle.running("oof")
            if event.type == pygame.MOUSEBUTTONDOWN:
                clicked()
                x, y = event.pos
                x -= 800-456//3
                y -= 600-390//3
                if startImg.get_rect().collidepoint(x, y):
                    soundOn *= -1
                    if soundOn == -1:
                        pygame.mixer.music.set_volume(0)
                    elif soundOn == 1:
                        pygame.mixer.music.set_volume(0.6)
                x, y = event.pos
                x -= 400-362*Sscale//2
                y -= 100
                if startImg.get_rect().collidepoint(x, y):
                    scene = "Setup"
                x, y = event.pos
                x -= 400-306*Sscale//2
                y -= 200
                if continueImg.get_rect().collidepoint(x, y):
                    scene = "Continue"
                x, y = event.pos
                x -= 400-512*Sscale//2
                y -= 300
                if HaCimg.get_rect().collidepoint(x, y):
                    scene = "HaC"

    elif scene == "HaC":
        superSetY = 600
        setY = 600
        notes = ["Isometric Dungeon Crawler", "", "Programmer : Fabian", "Art : Google (stolen from online)", "Sound : Forgot about that", "", "",  "Help Section", "", "To regain health you need to level up", "Leveling up increases HP and Attack", "It also increases the attack and health of monsters", "And it unlocks new monsters to figth!", "It is important to study the monster's Attack and HP curves"]
        while superSetY != 0:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    battle.running("oof")
            oof.BlackOut()
            for worth in range(0, len(notes)):
                what2blit = notes[worth]
                textsurface = myfont.render(what2blit, False, (120, 120, 120))
                oof.BlitIt(420-len(what2blit)*7, setY + 60*worth, textsurface)
            else:
                setY -= 1
                superSetY = setY +60*worth
            pygame.display.update()
            time.sleep(0.0166666666666666666666666666666666666666667)
        scene = "Menu"

    elif scene == "Setup":
        wepon = {"item1" : ["Bare Knuckle Fighting", "None", "Attack", 0]}

        imageName = "0" #screenshot save name

        ds = random.randint(4,15) #dungeon size --maximum 15--

        myplayer = player() #make myplayer the player object
        myplayer.image("frontright.png") #get an image for the player
        myplayer.imageScaler(0.5, 67, 130) #scale the player image

        myplayer.level_advancement(69, 0.7, 20) #create a xp curve
        print(myplayer.level_adv)
        myplayer.hp(100) #give the player an hp value
        myplayer.attack(5) #give the player an attack power
        myplayer.existance(0,0) #give the player an x and y location
        myplayer.xp(0)

        myplayer.levelsetup()

        myplayer.level_adaptor()

        dungeon = level(ds, ds) #dungeon size
        dungeon.image = pygame.image.load(asset_folder + "floor.png") #gather floor image
        dungeon.imageScaler(0.2, 271, 155) #scale the floor image

        dungeon.player_on(myplayer.x,myplayer.y)

        oriloc =  oof.sizeX/2 - dungeon.imageXsize/2 #original location
        original_location_for_the_y_axis_of_the_frickin_floor = 100
        wBx = oriloc
        wBy = original_location_for_the_y_axis_of_the_frickin_floor

        captureX = wBx + 12# - int(dungeon.imageXsize/2)
        captureY = wBy - 45 #- int(dungeon.imageYsize/2)

        scene = "Tileset"

    elif scene == "Continue":

        myplayer = player() #make myplayer the player object
        myplayer.image("frontright.png") #get an image for the player
        myplayer.imageScaler(0.5, 67, 130) #scale the player image

        wepon = pickle.load(open(sf+"wepon.curruptedFile", "rb"))
        imageName = pickle.load(open(sf+"imageName.curruptedFile", "rb"))
        ds = pickle.load(open(sf+"ds.curruptedFile", "rb"))
        myplayer.level_adv = pickle.load(open(sf+"myplayer.level_adv.curruptedFile", "rb"))
        myplayer.attack = pickle.load(open(sf+"myplayer.attack.curruptedFile", "rb"))
        myplayer.x = pickle.load(open(sf+"myplayer.x.curruptedFile", "rb"))
        myplayer.y = pickle.load(open(sf+"myplayer.y.curruptedFile", "rb"))
        myplayer.xp = pickle.load(open(sf+"myplayer.xp.curruptedFile", "rb"))
        myplayer.level = pickle.load(open(sf+"myplayer.level.curruptedFile", "rb"))
        myplayer.hp = pickle.load(open(sf+ "myplayer.hp.curruptedFile", "rb"))
        myplayer.level_adaptor() #makes a level!
        dungeon = level(ds, ds)
        dungeon.xmap = pickle.load(open(sf+"dungeon.xmap.curruptedFile", "rb"))
        dungeon.ymap = pickle.load(open(sf+"dungeon.ymap.curruptedFile", "rb"))
        dungeon.xPlayer = pickle.load(open(sf+"dungeon.xPlayer.curruptedFile", "rb"))
        dungeon.yPlayer = pickle.load(open(sf+"dungeon.yPlayer.curruptedFile", "rb"))

        dungeon.player_on(myplayer.x,myplayer.y)
        dungeon.image = pygame.image.load(asset_folder + "floor.png") #gather floor image
        dungeon.imageScaler(0.2, 271, 155) #scale the floor image

        oriloc =  oof.sizeX/2 - dungeon.imageXsize/2 #original location
        original_location_for_the_y_axis_of_the_frickin_floor = 100
        wBx = oriloc
        wBy = original_location_for_the_y_axis_of_the_frickin_floor

        captureX = wBx + 12# - int(dungeon.imageXsize/2)
        captureY = wBy - 45 #- int(dungeon.imageYsize/2)
        scene = "Tileset"

    elif scene == "Death":
        deathImg = pygame.image.load(asset_folder + "you_died.png")
        oof.BlitIt(0, 239, deathImg)
        battleUndergo = True
        click += 1
        if click == 120:
            scene = "Menu"

    elif scene == "Battle":
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                battle.running("off")
            if event.type == pygame.MOUSEBUTTONDOWN:
                clicked()
                x, y = event.pos
                y -= 520
                if clickableAttackImage.get_rect().collidepoint(x, y):
                    enemy.hp -= myplayer.attack + random.randint(-(myplayer.attack//2), (myplayer.attack//2))
                    myplayer.hp -= enemy.attack + random.randint(-(enemy.attack//2), (enemy.attack//2))
                x, y = event.pos
                x -= 550
                y -= 520
                if clickableRunImage.get_rect().collidepoint(x, y):
                    scene = "Tileset"
                x, y = event.pos
                x -= 270
                y -= 520
                if clickableDefendImage.get_rect().collidepoint(x, y):
                    hit = random.randint(1,3)
                    if hit == 1:
                        myplayer.hp -= enemy.attack + random.randint(-(enemy.attack//2), (enemy.attack//2))

        if battleUndergo == False:
            EC_Max = myplayer.level
            if EC_Max > len(enemies):
                EC_Max = len(enemies)
            EC = random.randint(1, EC_Max) #Enemy Choice
            MES = enemies["enemy" + str(EC)] #My Enemy Stats
            enemy = monster(MES[0], MES[1], MES[2])
            enemy.level_effector(myplayer.level-EC + 1, 0.4)
            enemy.image(MES[4])
            enemy.imageScaler(MES[9], MES[5], MES[6])
            battleUndergo = True
        oof.BlackOut()
        oof.BlitIt(0, 0, BackgroundImg)
        oof.BlitIt(MES[7], MES[8], enemy.image)
        what2blit = "Player HP : {0}".format(myplayer.hp)
        textsurface = myfont.render(what2blit, False, (120, 120, 120))
        oof.BlitIt(0, 0, textsurface)
        what2blit = "Enemy HP : {0}".format(enemy.hp)
        textsurface = myfont.render(what2blit, False, (120, 120, 120))
        oof.BlitIt(500, 0, textsurface)
        clickableAttackImage = pygame.image.load(asset_folder + "attack.png")
        oof.BlitIt(0, 520, clickableAttackImage)
        clickableDefendImage = pygame.image.load(asset_folder + "defend.png")
        oof.BlitIt(270, 521, clickableDefendImage)
        clickableRunImage = pygame.image.load(asset_folder + "run.png")
        oof.BlitIt(550, 521, clickableRunImage)

        if enemy.hp <= 0:
            scene = "Tileset"
            myplayer.xp += MES[3]
            myplayer.level_adaptor()
            battleUndergo = False
            del enemy
            if occorunce == True:
                what2blit = "Wepon" + str(random.randint(1, len(possipleWepons)))
                what2blit = possipleWepons[what2blit]
                weponNumber = len(wepon) + 1
                wepon["item" + str(weponNumber)] = what2blit
                occorunce = False

        elif myplayer.hp <= 0:
            scene = "Death"
            click = 0

    elif scene == "Escaped":
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                battle.running("off")
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    clicked()
                    scene = "Tileset"
                if event.key == pygame.K_RIGHT:
                    what2blit = "item" + str(itemDirectory)
                    what2blit = wepon[what2blit]
                    if what2blit[2] == "Attack":
                        myplayer.attack -= what2blit[3]
                    elif what2blit[2] == "Health":
                        myplayer.hp -= what2blit[3]
                    itemDirectory += 1
                    if what2blit[2] == "Attack":
                        myplayer.attack += what2blit[3]
                    elif what2blit[2] == "Health":
                        myplayer.hp += what2blit[3]
                    if itemDirectory > len(wepon):
                        itemDirectory = 1
                if event.key == pygame.K_SPACE:
                    if itemDescription == False:
                        itemDescription = True
                    else:
                        itemDescription = False
            if event.type == pygame.MOUSEBUTTONDOWN:
                clicked()
                x, y = event.pos
                x -= 800-159
                if saveImg.get_rect().collidepoint(x, y): #save
                    open(sf+"wepon.curruptedFile", 'w').close()
                    pickle.dump(wepon, open(sf+"wepon.curruptedFile", "wb"))
                    open(sf+"imageName.curruptedFile", 'w').close()
                    pickle.dump(imageName, open(sf+"imageName.curruptedFile", "wb"))
                    open(sf+"ds.curruptedFile", 'w').close()
                    pickle.dump(ds, open(sf+"ds.curruptedFile", "wb"))
                    open(sf+"myplayer.level_adv.curruptedFile", 'w').close()
                    pickle.dump(myplayer.level_adv, open(sf+"myplayer.level_adv.curruptedFile", "wb"))
                    open(sf+"myplayer.attack.curruptedFile", 'w').close()
                    pickle.dump(myplayer.attack, open(sf+"myplayer.attack.curruptedFile", "wb"))
                    open(sf+"myplayer.x.curruptedFile", 'w').close()
                    pickle.dump(myplayer.x, open(sf+"myplayer.x.curruptedFile", "wb"))
                    open(sf+"myplayer.y.curruptedFile", 'w').close()
                    pickle.dump(myplayer.y, open(sf+"myplayer.y.curruptedFile", "wb"))
                    open(sf+"dungeon.xmap.curruptedFile", 'w').close()
                    pickle.dump(dungeon.xmap, open(sf+"dungeon.xmap.curruptedFile", "wb"))
                    open(sf+"dungeon.ymap.curruptedFile", 'w').close()
                    pickle.dump(dungeon.ymap, open(sf+"dungeon.ymap.curruptedFile", "wb"))
                    open(sf+"dungeon.xPlayer.curruptedFile", 'w').close()
                    pickle.dump(dungeon.xPlayer, open(sf+"dungeon.xPlayer.curruptedFile", "wb"))
                    open(sf+"dungeon.yPlayer.curruptedFile", 'w').close()
                    pickle.dump(dungeon.yPlayer, open(sf+"dungeon.yPlayer.curruptedFile", "wb"))
                    open(sf+"myplayer.xp.curruptedFile", 'w').close()
                    pickle.dump(myplayer.xp, open(sf+"myplayer.xp.curruptedFile", "wb"))
                    open(sf+"myplayer.level.curruptedFile", 'w').close()
                    pickle.dump(myplayer.level, open(sf+"myplayer.level.curruptedFile", "wb"))
                    open(sf+"myplayer.hp.curruptedFile", 'w').close()
                    pickle.dump(myplayer.hp, open(sf+"myplayer.hp.curruptedFile", "wb"))
        oof.BlackOut()
        oof.BlitIt(800-159, 0, saveImg)
        what2blit = "HP : {0}".format(myplayer.hp)
        textsurface = myfont.render(what2blit, False, (120, 120, 120))
        oof.BlitIt(0, 0, textsurface)
        what2blit = "Level : {0}".format(myplayer.level)
        textsurface = myfont.render(what2blit, False, (120, 120, 120))
        oof.BlitIt(200, 0, textsurface)
        what2blit = "XP : {0}".format(myplayer.xp)
        textsurface = myfont.render(what2blit, False, (120, 120, 120))
        oof.BlitIt(400, 0, textsurface)
        what2blit = "item" + str(itemDirectory)
        what2blit = wepon[what2blit]
        what2blit = what2blit[1]
        textsurface = myfont.render(what2blit, False, (120, 120, 120))
        oof.BlitIt(0, 100, textsurface)
        anotherKeepSafeForHeight = 0
        onceAgainAnotherKeepSafe = 0

        if itemDescription == True:
            what2blit = "item" + str(itemDirectory)
            what2blit = wepon[what2blit]
            what2blit = "It increases {0} by {1}.".format(what2blit[2], what2blit[3])

            textsurface = myfont.render(what2blit, False, (120, 120, 120))
            oof.BlitIt(0, 170, textsurface)
            what2blit = "item" + str(itemDirectory)
            what2blit = wepon[what2blit]
            what2blit = "{0}".format(what2blit[0])
            textsurface = myfont.render(what2blit, False, (120, 120, 120))
            oof.BlitIt(0, 170+60, textsurface)

            """
            keepSafe = what2blit
            del anotherKeepSafeForHeight
            del onceAgainAnotherKeepSafe
            for description in range(-1, len(what2blit)//43 - 1):
                what2blit = keepSafe[(description+1)*43: (description+1)*43 + 43]
                textsurface = myfont.render(what2blit, False, (120, 120, 120))
                oof.BlitIt(0, (description + 3) * 69, textsurface)
                anotherKeepSafeForHeight = (description + 3) * 69
                onceAgainAnotherKeepSafe = (description+1)*43 + 44
            else:
                try:
                    what2blit = keepSafe[onceAgainAnotherKeepSafe:]
                    textsurface = myfont.render(what2blit, False, (120, 120, 120))
                    oof.BlitIt(0, anotherKeepSafeForHeight+100, textsurface)
                except:
                    textsurface = myfont.render(what2blit, False, (120, 120, 120))
                    oof.BlitIt(0, 150, textsurface)
                """

    elif scene == "Tileset":

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                battle.running("off")
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    if downKey == True:
                        pass
                    elif downKey == False:
                        downKey = True
                        myplayer.direction(-1)
                        myplayer.imageScaler(0.5, 67, 130)
                elif event.key == pygame.K_RIGHT:
                    if downKey == True:
                        pass
                    elif downKey == False:
                        downKey = True
                        myplayer.direction(1)
                        myplayer.imageScaler(0.5, 67, 130)
                elif event.key == pygame.K_UP:
                    if downKey == True:
                        pass
                    elif downKey == False:
                        downKey = True
                        myplayer.move_forward()
                        scene = myplayer.scenePrep
                        print(scene)
                        #print(dungeon.ymap)
                elif event.key == pygame.K_s:
                    imageName = str((int(imageName)+1))
                    pygame.image.save(oof.display, "screenshots/" + imageName + ".png")
                elif event.key == pygame.K_ESCAPE:
                    clicked()
                    scene = "Escaped"
            if event.type == pygame.KEYUP:
                if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT or event.key == pygame.K_UP:
                    downKey = False

        #pygame.event.pump()
        oof.BlackOut()
        #oof.BlitIt(captureX, captureY, dungeon.image)

        for i in range(1,len(dungeon.ymap)+1):
            #work = True --see next triple quote to know use--
            for q in range(1,len(dungeon.xmap)+1):
                """
                if (i == 1 or i == len(dungeon.ymap)) and (q == len(dungeon.xmap)//2+1):
                    dungeon.image = pygame.image.load(asset_folder + "darkfloor.png")
                    dungeon.imageScaler(0.2, 271, 155)
                    oof.BlitIt(wBx, wBy, dungeon.image)
                    dungeon.image = pygame.image.load(asset_folder + "floor.png")
                    dungeon.imageScaler(0.2, 271, 155)
                    #print("Succesful Planting")

                elif (q == 1 or q == len(dungeon.xmap)) and (i == len(dungeon.ymap)//2+1):
                    dungeon.image = pygame.image.load(asset_folder + "darkfloor.png")
                    dungeon.imageScaler(0.2, 271, 155)
                    oof.BlitIt(wBx, wBy, dungeon.image)
                    dungeon.image = pygame.image.load(asset_folder + "floor.png")
                    dungeon.imageScaler(0.2, 271, 155)
                    #print("Succesful Planting")
                else:
                    oof.BlitIt(wBx, wBy, dungeon.image)
                    """
                oof.BlitIt(wBx, wBy, dungeon.image)
                #--------------------print(str(wBx) + " " + str(wBy) + " " + dungeon.xmap[q-1] + dungeon.ymap[i-1])
                if (dungeon.ymap[i-1] == "X") and (dungeon.xmap[q-1] == "X"):
                    #print(str(wBx) + " " + str(wBy))
                    captureX = wBx + 12# - int(dungeon.imageXsize/2)
                    captureY = wBy - 45 #- int(dungeon.imageYsize/2)
                    #--------------------print(captureY)
                    #-------------------------print("hi *kirby")
                wBx += int(dungeon.imageXsize/2)
                wBy += int(dungeon.imageYsize/2)
            else:
                wBx = oriloc
                wBy = original_location_for_the_y_axis_of_the_frickin_floor
                wBx -= i * int(dungeon.imageXsize/2)
                wBy += i * int(dungeon.imageYsize/2)
                #-----------------------------------print(i)

        else: #This else loop didnt use to be here so the character would starts at the wrong point
            wBx = oriloc
            wBy = original_location_for_the_y_axis_of_the_frickin_floor

        if myplayer.moved == True:
            myplayer.moved == False
            event = random.randint(1, 100)

        """ #use with one space rooms --its glitchy and something is wrong with the players location. i dont need a one space room as there is no where to go anyway--
        if work == False:
            for i in range(1,2):
                work = True
                for q in range(1,2):
                    oof.BlitIt(wBx, wBy, dungeon.image)
                    if (dungeon.ymap[i-1] == "X") and (dungeon.xmap[q-1] == "X"):
                    #if (i == 1) and (q == 1):
                        captureX = wBx + 12
                        captureY = wBy - 45
                    wBx += int(dungeon.imageXsize/2)
                    wBy += int(dungeon.imageYsize/2)
                else:
                    wBx = oriloc
                    wBy = original_location_for_the_y_axis_of_the_frickin_floor
                    wBx -= i * int(dungeon.imageXsize/2)
                    wBy += i * int(dungeon.imageYsize/2)
                    """

        """
        click+=1
        if click == 120:
            click = 0
            ds = random.randint(2,15) #dungeon size --maximum 15--
        """
        #print(dungeon.xmap)
        #print(dungeon.ymap)
        dungeon.change_layout(ds, ds)
        #print(ds)
        #------------------------------------print(str(captureX) + " " + str(captureY))
        dungeon.player_on(myplayer.x, myplayer.y)
        oof.BlitIt(captureX, captureY, myplayer.image)
    pygame.display.update()
    oof.clock.tick(60)

#left and right arrows to change directions and spacebar to move forward!!! --idea inspired from dad-- *I was planning on using isometric keyboard input but realised I had none :(. Maybe 7, 9, 1 and 3?

#x and y axis
#      x   x   x   x
#    y
#   y
#  y
# y


from openai import OpenAI
import os
import json
import jsonlines
import time
import csv
from dotenv import load_dotenv
from collections import defaultdict
from pydantic import BaseModel
from io import StringIO

load_dotenv()

# Set your API key
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

def valid_data_jsonl(data_path, isTrainingData):
    print("\033[0m" + "Starting valid_data_jsonl...")
    try:
        # Load the dataset
        with open(data_path, 'r', encoding='utf-8') as f:
            dataset = [json.loads(line) for line in f]

        # Initial dataset stats
        print("Num examples:", len(dataset))
        print("First example:")
        for message in dataset[0]["messages"]:
            print(message)

        # Format error checks
        format_errors = defaultdict(int)

        for ex in dataset:
            if not isinstance(ex, dict):
                format_errors["data_type"] += 1
                continue

            messages = ex.get("messages", None)
            if not messages:
                format_errors["missing_messages_list"] += 1
                continue

            for message in messages:
                if "role" not in message or "content" not in message:
                    format_errors["message_missing_key"] += 1

                if any(k not in ("role", "content", "name", "function_call") for k in message):
                    format_errors["message_unrecognized_key"] += 1

                if message.get("role", None) not in ("system", "user", "assistant", "function"):
                    format_errors["unrecognized_role"] += 1

                content = message.get("content", None)
                function_call = message.get("function_call", None)

                if (not content and not function_call) or not isinstance(content, str):
                    format_errors["missing_content"] += 1

            if isTrainingData:
                if not any(message.get("role", None) == "assistant" for message in messages):
                    format_errors["example_missing_assistant_message"] += 1

        if format_errors:
            print("Found errors:")
            for k, v in format_errors.items():
                print(f"{k}: {v}")
            return False

    except FileNotFoundError:
        print("\033[91m\u2718 " + f"The file '{data_path}' was not found.")
        return False

    except Exception as e:
        print("\033[91m\u2718 " + f"An error occurred: {e}")
        return False

    print("\033[92m\u2714 " + "No errors found")
    return True

def add_prompt_to_jsonl_file(input_file, output_file, prompt):
    print("\033[0m" + "Starting add_prompt_to_jsonl_file...")
    try:
        with jsonlines.open(input_file, 'r') as reader, jsonlines.open(output_file, 'w') as writer:
            for line in reader:
                messages = line.get('messages', [])
                if messages:
                    messages.insert(0, {'role': 'system', 'content': prompt})
                line['messages'] = messages
                writer.write(line)

    except Exception as e:
        print("\033[91m\u2718 " + f"An error occurred: {e}")
        return None

    print("\033[92m\u2714 " + f"Jsonl dataset with prompt saved in {output_file}")
    return output_file

def upload_file(file_path):
    print("\033[0m" + "Starting upload_file...")
    try:
        file_uploaded = client.files.create(file=open(file_path, "rb"), purpose='fine-tune')

        while True:
            print("Waiting for file to process...")
            file_handle = client.files.retrieve(file_uploaded.id)
            if file_handle and file_handle.status == "processed":
                print("\033[92m\u2714 " + "File processed")
                break
            time.sleep(120)

    except Exception as e:
        print("\033[91m\u2718 " + f"An error occurred: {e}")
        return None

    print("\033[92m\u2714 " + "File uploaded")
    return file_uploaded

def create_json_file(path, file_name, content):
    print("\033[0m" + "Starting create_json_file...")
    try:
        directory = os.path.join(path, os.path.dirname(file_name))
        if not os.path.exists(directory):
            os.makedirs(directory)

        existing_files = [item_file for item_file in os.listdir(path) if item_file.startswith(file_name) and item_file.endswith('.json')]
        next_number = 0 if not existing_files else len(existing_files) + 1
        file_name = f'{file_name}{next_number}.json'

        with open(os.path.join(path, file_name), 'w') as result_file:
            json.dump(content, result_file, indent=4)

    except Exception as e:
        print("\033[91m\u2718 " + f"An error occurred: {e}")
        return None

    print("\033[92m\u2714 " + f"Results saved in {path}{file_name}")
    return result_file

def create_csv_file(path, file_name, content):
    print("\033[0m" + "Starting create_csv_file...")
    try:
        directory = os.path.join(path, os.path.dirname(file_name))
        if not os.path.exists(directory):
            os.makedirs(directory)

        existing_files = [item_file for item_file in os.listdir(path) if item_file.startswith(file_name) and item_file.endswith('.csv')]
        next_number = 0 if not existing_files else len(existing_files) + 1
        file_name = f'{file_name}{next_number}.csv'

        lines = content.split('\n')
        data = [line.split(',') for line in lines]

        with open(os.path.join(path, file_name), 'w', newline='') as result_file:
            csv_writer = csv.writer(result_file)
            csv_writer.writerows(data)

    except Exception as e:
        print("\033[91m\u2718 " + f"An error occurred: {e}")
        return None

    print("\033[92m\u2714 " + f"Results saved in {path}{file_name}")
    return result_file

def create_csv_file_from_array(path, file_name, content):
    print("\033[0m" + "Starting create_csv_file_from_array...")
    try:
        directory = os.path.join(path, os.path.dirname(file_name))
        if not os.path.exists(directory):
            os.makedirs(directory)

        existing_files = [item_file for item_file in os.listdir(path) if item_file.startswith(file_name) and item_file.endswith('.csv')]
        next_number = 0 if not existing_files else len(existing_files) + 1
        file_name = f'{file_name}{next_number}.csv'

        fieldnames = ['User review', 'Emotion for chat completion with temperature 0.2', 'Emotion for chat completion with temperature 0.8']

        with open(os.path.join(path, file_name), 'w', newline='') as result_file:
            writer = csv.writer(result_file)
            writer.writerow(fieldnames)
            writer.writerows(content)

    except Exception as e:
        print("\033[91m\u2718 " + f"An error occurred: {e}")
        return None

    print("\033[92m\u2714 " + f"Results saved in {path}{file_name}")
    return result_file

def create_fine_tuning_job(file_uploaded, model):
    print("\033[0m" + "Starting create_fine_tuning_job...")
    try:
        fine_tuning_job = client.fine_tuning.jobs.create(training_file=file_uploaded.id, model=model)

        status = fine_tuning_job.status
        if status not in ["succeeded", "failed"]:
            print("Waiting for fine-tuning to complete...")
            while status not in ["succeeded", "failed"]:
                time.sleep(60)
                fine_tuning_job = client.fine_tuning.jobs.retrieve(fine_tuning_job.id)
                status = fine_tuning_job.status
                print("Status: ", status)

        print("\033[92m\u2714 " + f"Fine-tune job {fine_tuning_job.id} finished with status: {status}")

    except Exception as e:
        print("\033[91m\u2718 " + f"An error occurred: {e}")
        return None

    fine_tuning_job_serializable = fine_tuning_job.model_dump()
    create_json_file("results/", "fine_tuning_job_result_", fine_tuning_job_serializable)

    if create_json_file is None:
            print("\033[91m\u2718 " + "Error in create_json_file")
            return None

    return fine_tuning_job

def chat_completion(model, messages, temperature):
    print("\033[0m" + "Starting chat_completion...")
    try:
        completion = client.chat.completions.create(
            model=model,
            messages=messages,
            temperature=temperature
        )

    except Exception as e:
        print("\033[91m\u2718 " + f"An error occurred: {e}")
        return None

    print("\033[92m\u2714 " + f'Completion with temperature {temperature}: ', completion.choices[0].message.content)
    return completion

def convert_to_serializable(item):
    try:
        if isinstance(item, set):
            return list(item)
        else:
            return item

    except Exception as e:
        print("\033[91m\u2718 " + f"An error occurred: {e}")
        return None

def generate_chat_completion_results(model, dataset_path):
    print("\033[0m" + "Starting generate_chat_completion_results...")
    try:
        generated_completion = []
        with open(dataset_path, "r") as test_data:
            for line in test_data:
                data = json.loads(line)
                data_message = data.get("messages")
                user_review = data_message[1].get("content")
                print("\033[0m" + 'User review: ', user_review)

                completion_low_temperature = chat_completion(model, data_message, 0.2)
                if chat_completion is None:
                    print("\033[91m\u2718 " + "Error in chat completion with temperature 0.2")
                    return None
                completion_high_temperature = chat_completion(model, data_message, 0.8)
                if chat_completion is None:
                    print("\033[91m\u2718 " + "Error in chat completion with temperature 0.8")
                    return None

                result = [user_review, completion_low_temperature.choices[0].message.content, completion_high_temperature.choices[0].message.content]
                generated_completion.append(result)

        generated_completion = [convert_to_serializable(item) for item in generated_completion]
        if generated_completion is None:
            print("\033[91m\u2718 " + "Error in convert_to_serializable")
            return None

        # NOTE: You can change this to create a json file instead of a csv file
        """create_json_file("results/", "chat_completion_result_", generated_completion)
        if create_json_file is None:
            print("\033[91m\u2718 " + "Error in create_json_file")
            return None
        """

        chat_completion_result = create_csv_file_from_array("results/", "chat_completion_result_", generated_completion)
        if chat_completion_result is None:
            print("\033[91m\u2718 " + "Error in create_csv_file")
            return None

        return chat_completion_result

    except Exception as e:
        print("\033[91m\u2718 " + f"An error occurred: {e}")
        return None

def refactor_id_jsonl(jsonl_file):
    print("\033[0m" + "Starting refactor_id_jsonl...")
    try:
        id_count = {}
        updated_lines = []

        with open(jsonl_file, 'r') as reader:
            lines = reader.readlines()

        for line in lines:
            data = json.loads(line)
            current_id = data.get('id')

            if current_id in id_count:
                id_count[current_id] += 1
                data['id'] = f"{current_id}_{id_count[current_id]}"
            else:
                id_count[current_id] = 0

            updated_lines.append(json.dumps(data))

        with open(jsonl_file, 'w') as writer:
            for updated_line in updated_lines:
                writer.write(f"{updated_line}\n")

    except Exception as e:
        print("\033[91m\u2718 " + f"An error occurred: {e}")
        return None

    print("\033[92m\u2714 " + f'IDs processed in {jsonl_file}')

def add_emotion_and_id_to_csv(jsonl_file, csv_file):
    print("\033[0m" + "Starting add_emotion_and_id_to_csv...")
    try:
        emotions = {}
        ids = []

        # Abre el archivo CSV como objeto
        with open(csv_file.name, 'r+', newline='', encoding='utf-8') as file:
            csv_data = StringIO(file.read())  # Crear un StringIO con el contenido del archivo CSV
            csv_data.seek(0)  # Asegurarse de que el puntero esté al inicio

            csv_reader = csv.reader(csv_data)
            csv_list = list(csv_reader)

            header = csv_list[0]
            header.insert(0, 'ID')
            header.append('Emotion label')

            csv_data.seek(0)  # Mover el puntero al inicio del StringIO

            with jsonlines.open(jsonl_file, 'r') as reader:
                for line in reader:
                    ids.append(line["id"])
                    emotions[line["id"]] = line["emotion"]

            for i, row in enumerate(csv_list[1:], start=1):
                row.insert(0, ids[i - 1])
                emotion = emotions.get(ids[i - 1], '')
                row.append(emotion)

            csv_data.seek(0)  # Mover el puntero al inicio del StringIO

            writer = csv.writer(csv_data)
            writer.writerows(csv_list)

            # Actualizar el contenido del archivo CSV
            file.seek(0)
            file.write(csv_data.getvalue())
            file.truncate()  # Truncar el archivo si es necesario

    except Exception as e:
        print("\033[91m\u2718 " + f"An error occurred: {e}")
        return None

    print("\033[92m\u2714 " + "IDs and emotions added")
    return csv_file

def main():
    print("Starting main...")
    # NOTE: You can change this to any dataset you want to fine-tune on
    training_dataset = "./data/training_dataset.jsonl"
    # NOTE: You can change this to any dataset you want to test
    test_dataset = "./data/test_dataset.jsonl"

    if not valid_data_jsonl(training_dataset, True) or not valid_data_jsonl(test_dataset, False):
        return

    # Add prompt to training file
    system_prompt = "Can you tell me what emotion is expressing the message above? It can be one of the following: happiness, sadness, anger, fear, surprise, disgust or not-relevant (if it doesn't express any relevant emotion)."
    training_dataset_with_prompt = add_prompt_to_jsonl_file(training_dataset, "data/training_dataset_with_prompt.jsonl", system_prompt)
    if training_dataset_with_prompt is None:
        return

    # Upload training file
    file_uploaded = upload_file(training_dataset_with_prompt)
    if file_uploaded is None:
        return

    # Create fine-tuning job
    model = "gpt-3.5-turbo"
    fine_tuned_job = create_fine_tuning_job(file_uploaded, model)
    if fine_tuned_job is None:
        return

    # Get the metrics
    result_files_id = fine_tuned_job.result_files[0]
    content = client.files.retrieve_content(result_files_id)
    csv_file = create_csv_file("results/", "training_metrics_", content)
    if csv_file is None:
        return

    # Add prompt to test file
    test_dataset_with_prompt = add_prompt_to_jsonl_file(test_dataset, "data/test_dataset_with_prompt.jsonl", system_prompt)
    if test_dataset_with_prompt is None:
        return

    # Create chat completion and generate result file
    model = fine_tuned_job.fine_tuned_model
    csv_results_file = generate_chat_completion_results(model, test_dataset_with_prompt)
    if csv_results_file is None:
        return

    # Add ID & emotion to csv file
    emotion_labels_path = "./data/emotion_labels_test_dataset.jsonl"
    refactor_id_jsonl(emotion_labels_path)
    csv_results_file = add_emotion_and_id_to_csv(emotion_labels_path, csv_results_file)
    if csv_results_file is None:
        return

    print("\033[92m\u2714 " + "The program has finished successfully")

if __name__ == '__main__':
    main()


from typing import Callable

import torch
from torch import Tensor

from thre3d_atom.rendering.volumetric.render_interface import (
    Rays,
    ProcessedPointsOnRays,
    RenderOut,
)
from thre3d_atom.utils.constants import (
    ZERO_PLUS,
    INFINITY,
    EXTRA_ACCUMULATED_WEIGHTS,
    EXTRA_POINT_WEIGHTS,
    EXTRA_POINT_DEPTHS,
    EXTRA_POINT_OCCUPANCIES,
    EXTRA_POINT_DENSITIES,
    EXTRA_SAMPLE_INTERVALS,
    EXTRA_DISPARITY,
)

def density2occupancy_pb(densities: Tensor, deltas: Tensor) -> Tensor:
    """computes occupancy values from density values in the range [0, inf).
    The occupancy (being a probability) is always strictly between [0, 1].
    This function is physically based, and can be derived from Lambert's law"""
    return 1.0 - torch.exp(-(densities * deltas))

def accumulate_radiance_density_on_rays(
    processed_points: ProcessedPointsOnRays,
    rays: Rays,
    stochastic_density_noise_std: float = 1.0,
    density2occupancy: Callable[[Tensor, Tensor], Tensor] = density2occupancy_pb,
    radiance_hdr_tone_map: Callable[[Tensor], Tensor] = torch.sigmoid,
    white_bkgd: bool = True,
    extra_debug_info: bool = False,
) -> RenderOut:
    dtype, device = processed_points.points.dtype, processed_points.points.device

    # unpack the radiance and density from the processed points
    raw_radiance, raw_density = (
        processed_points.points[..., :-1],
        processed_points.points[..., -1],
    )

    # compute sample-intervals for ray-time integration
    deltas = processed_points.depths[..., 1:] - processed_points.depths[..., :-1]
    inf_delta = torch.full(
        size=(*deltas.shape[:-1], 1), fill_value=INFINITY, dtype=dtype, device=device
    )
    deltas = torch.cat([deltas, inf_delta], dim=-1)  # [N_rays, N_samples]
    # need proper deltas in coordinate domain space, hence normalizing ray-dir norms
    deltas = deltas * rays.directions[..., None, :].norm(dim=-1)

    # add stochastic noise to density if requested :).
    # can be used to regularize repr during training (kind-of-sort-of prevents floater artifacts).
    density_noise = (
        torch.randn(raw_density.shape, dtype=dtype, device=device)
        * stochastic_density_noise_std
    )
    alpha = density2occupancy(raw_density + density_noise, deltas)

    # compute the radiance weights for accumulation along the ray
    ones = torch.ones((alpha.shape[0], 1), dtype=dtype, device=device)
    weights = alpha * torch.cumprod(torch.cat([ones, 1.0 - alpha], -1), -1)[:, :-1]

    # accumulate the predicted radiance values of the samples using the computed alphas
    colour = radiance_hdr_tone_map(raw_radiance)
    # dims below: [N, NUM_COLOUR_CHANNELS]
    colour_render = torch.sum(colour * weights[..., None], dim=-2)

    # sum of weights along each ray, should ideally be 1.0 everywhere
    acc_render = torch.sum(weights, dim=-1, keepdim=True)

    if white_bkgd:
        # add a white background if requested. Mathematically, note that we assume
        # the background to be emitting a solid bright white colour RGB=(1.0, 1.0, 1.0)
        # hence the simplification of the alpha-composition formula :)
        colour_render = colour_render + (1 - acc_render)

    # compute depth_render and disparity_render (inverse depth)
    depth_render = (processed_points.depths * weights).sum(dim=-1, keepdims=True)
    disparity_render = 1.0 / torch.maximum(
        torch.full(acc_render.shape, ZERO_PLUS, device=depth_render.device),
        depth_render / acc_render,
    )

    # additional renders
    extra_dict = {
        EXTRA_DISPARITY: disparity_render,
        EXTRA_ACCUMULATED_WEIGHTS: acc_render,
    }

    if extra_debug_info:
        # adds very big tensor buffers
        # num samples per ray (or ray-chunk). Please only use for debugging purposes
        extra_dict.update(
            {
                EXTRA_POINT_DENSITIES: raw_density,
                EXTRA_POINT_OCCUPANCIES: alpha,
                EXTRA_POINT_WEIGHTS: weights,
                EXTRA_POINT_DEPTHS: processed_points.depths,
                EXTRA_SAMPLE_INTERVALS: deltas,
            }
        )

    return RenderOut(
        colour=colour_render,
        depth=depth_render,
        extra=extra_dict,
    )


from flask import Flask, render_template, request, Response, send_from_directory, redirect, url_for, jsonify
from flask_sslify import SSLify
from flask_cors import CORS
import os
from PIL import Image
import json
import base64
import cv2
import numpy as np
#from src import classifier
import web_face_recognition
import time
import subprocess as sp
import requests
import threading
from pymongo import MongoClient
from threading import Thread

app = Flask(__name__)
sslify = SSLify(app)
CORS(app)
save_path = str('/work/MachineLearning/my_dataset/wos_event/')
client = MongoClient('mongodb://localhost:27017/')
#Accessing databases
db = client['attendance']
name_list = db['name_list']

# added to put object in JSON
class Object(object):
    def __init__(self):
        self.name = "Queue list"

    def toJSON(self):
        return json.dumps(self.__dict__)

@app.after_request
def after_request(response):
    response.headers.add('Access-Control-Allow-Origin', '*')
    response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
    response.headers.add('Access-Control-Allow-Methods', 'GET,POST,OPTIONS')
    return response

@app.route('/')
def index():
    return Response(os.getcwd())

@app.route('/recognition')
def start():
    return Response(open('/work/MachineLearning/facenet_m360/contributed/templates/single_shot_recognition.html').read(), mimetype="text/html")

@app.route('/enrol', methods=['POST'])
def enrol():
    try:
        if request.method == 'POST':
            print('POST /enrol success!')

        image_file = json.loads(request.data)
        name = str(image_file['id'])

        if not os.path.exists(os.path.join(save_path+name)):
            os.mkdir(save_path+name)

        web_face_recognition.append_queue(name)
        count = 0
        for images in image_file['data']:
            filename = name + str(count)
            img = base64.b64decode(images)
            img_array = np.fromstring(img, np.uint8)
            imgdata = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
            rgb_frame = imgdata[:, :, ::-1]
            img = Image.fromarray(rgb_frame, "RGB")
            if img is not None:
                img.save(os.path.join(save_path+name+'/'+filename+".jpg"))
            count += 1

        if web_face_recognition.run() is False:
            web_face_recognition.enrol(incremental=True)

        return redirect(url_for('getStatus', _external=True, _scheme='https'))

    except Exception as e:
        print('POST /enrol error : %s' % e)
        return e

@app.route('/getStatus', methods=['GET', 'POST'])
def getStatus():
    try:
        output = []
        queue = web_face_recognition.get_status()

        return queue

    except Exception as e:
        print('Check status failed : %s' % e)
        return e

@app.route('/recognition_result', methods=['POST'])
def face_recognition():
    try:
        image_file = json.loads(request.data.decode('utf-8'))
        img = base64.b64decode(image_file['data'])
        img_array = np.fromstring(img, np.uint8)
        imgdata = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
        boxes = web_face_recognition.recognize(imgdata)
        boxes['name'] = name_list.find_one({'person': boxes['name']})

        return boxes

    except Exception as e:
        print('Recognition failed : %s' % e)
        return e

if __name__ == '__main__':
    #start_runner()
    app.run(host="0.0.0.0", port=8081, threaded=True, ssl_context='adhoc')
    #app.run(host='0.0.0.0', port=8081, threaded=True, debug=True, ssl_context="adhoc")


"""
Create the figure for the load growths for the linear and non-linear case.
Also add the plot for the PV growth that it is lineal.
"""

import pickle
import pandas as pd
from core.scenarios import ScenarioGenerator
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
from matplotlib.patches import Rectangle, Circle
from scipy.interpolate import UnivariateSpline, interp1d, pchip_interpolate
from core.figure_utils import set_figure_art
import matplotlib.pyplot as plt
import matplotlib

set_figure_art()
plt.rc('text', usetex=True)
plt.rc('text.latex', preamble=r'\usepackage{amsmath}')
# matplotlib.verbose.level = 'debug-annoying'

class OOMFormatter(mticker.ScalarFormatter):
    def __init__(self, order=0, fformat='%1.1f', offset=True, mathText=True):
        self.oom = order
        self.fformat = fformat
        mticker.ScalarFormatter.__init__(self,useOffset=offset,useMathText=mathText)
    def _set_order_of_magnitude(self):
        self.orderOfMagnitude = self.oom
    def _set_format(self, vmin=None, vmax=None):
        self.format = self.fformat
        if self._useMathText:
            self.format = r'$\mathdefault{%s}$' % self.format

def retrieve_energy_limits(scenario_generator):
    nodes_per_cluster = scenario_generator.nodes_per_cluster

    minimums_cluster = []
    maximus_cluster = []

    for ii in range(scenario_generator.n_clusters):
        minimums_cluster = minimums_cluster + \
                           [min(scenario_generator.mapper_load_growth[ii].values()) * nodes_per_cluster.loc[ii]]
        maximus_cluster = maximus_cluster + \
                          [max(scenario_generator.mapper_load_growth[ii].values()) * nodes_per_cluster.loc[ii]]

    data_frame = {"type_bus": list(range(scenario_generator.n_clusters)),
                  "minimums": minimums_cluster,
                  "maximums": maximus_cluster}

    energy_limits = pd.DataFrame(data_frame)
    energy_limits.set_index('type_bus', inplace=True)

    return energy_limits

def normalize_and_inverse(min_, max_):
    """
    Creates a normalizer function and its inverse that maps a value in GWh/Year to fraction of
    percentage, i.e., [0,1]

    Parameters:
    ----------
        min_: float: Minimum annual energy consumption per year of the whole grid [GWh/year]
        max_: float: Maximum annual energy consumption per year of the whole grid [GWh/year]
    """

    # f =      lambda x: np.round(np.clip(( (x - min_)/(max_ - min_) ), 0 , 1), 20)  #  y = (x-xmin)/(xmax - xmin)   : Function  [0.0 - 1.0]
    f = lambda x: np.round(np.clip(((x - min_) / (max_ - min_)),
                                   -0.5, 1.5),
                           20)  # y = (x-xmin)/(xmax - xmin)   : Function  [0.0 - 1.0]
    f_inv =  lambda x: ( x * (max_ - min_) + min_ )  #  x = y*(xmax-xmin) + xmin   : Inverse Function [0-1] -> [min, max]

    return f, f_inv

def growth_curve_normalized(x=None, y=None, k=3, curve="spline"):
    """
    Create a growth function with support [0,1] and range [0,1].

    Parameters:
    -----------
        x: np.ndarray: Control points for the interpolation that corresponds to the x-axis if curve=="spline"
        y: np.ndarray: Control points for the interpolation that corresponds to the y-axis if curve=="spline"
        k: int: Degree of the spline to fit.
        curve: str: Type of interpolation for the control points.
            The options are: ["spline", "lineal", "root", "square"]

    Returns:
    --------
        g_normalized: Function g() that maps any value between [0,1] to a range of [0,1]
            Example: to use the function just type g(vale).

    """

    if curve == "spline":
        assert k is not None, "Spline degree must be defined."
        g_normalized = UnivariateSpline(x, y, k=k)
    elif curve == "lineal":
        cp = np.array([(0,0),
                       (1,1)])
        g_normalized = interp1d(cp[:,0], cp[:,1])
    elif curve == "root":
        g_normalized = lambda x: np.sqrt(x)

    elif curve == "square":
        g_normalized = lambda x: x ** 2

    elif curve == "corrected":
        g_normalized = lambda w: np.clip(pchip_interpolate(x, y, w), 0, 1)

    else:
        raise NotImplementedError

    if curve != "corrected":
        assert np.allclose(g_normalized(0), 0, atol=0.01), "The non-lineal function should map closed to f(0) == 0.0"
        assert np.allclose(g_normalized(1), 1, rtol=0.01), "The non-lineal function should map closed to f(1) == 1.0"

    return g_normalized

def growth_curve(g_normalized, min_, max_):
    """
    Computes the de-normalization of the normalized growth curve g() to values in GWh/year, also computes a
    """

    g = lambda x: g_normalized(x) * (max_ - min_) + min_

    x = np.linspace(0.0, 1.0, 100000)
    y = g(x)  # Values in kw

    # Nearest value procedure: The function returns a value between [0,1]
    g_inv = lambda w: np.round(x[[np.argmin(np.abs(y - w_)) for w_ in w]], 20)  # w: Values in GWh/year.

    return g, g_inv

file_name_load_models = r"../models/copula_model_load.pkl"
with open(file_name_load_models, "rb") as pickle_file:
    copula_load = pickle.load(pickle_file)

file_name_irradiance_models = r"../models/copula_model_irradiance.pkl"
with open(file_name_irradiance_models, "rb") as pickle_file:
    mixture_model_irradiance = pickle.load(pickle_file)

file_name_network = r"../data/processed_data/network_data/Nodes_34.csv"
grid = pd.read_csv(file_name_network)
grid_info = grid.iloc[1:, :]  # Drop the slack node

#%%
#======================================================================================================================
# CREATE MODEL FOR THE LINEAL CASE
#======================================================================================================================
scenario_generator = ScenarioGenerator(copula_load=copula_load,
                                       mixture_model_irradiance=mixture_model_irradiance,
                                       grid_info=grid_info,
                                       n_levels_load_growth=10,
                                       n_levels_pv_growth=10,
                                       n_levels_mixtures=10)

#======================================================================================================================
# CREATE MODEL FOR THE NON LINEAL CASE
#======================================================================================================================

#%% Spline function
# Control points for the spline
points = np.array([(0.0, 0.0),
                   (0.3, 0.4),
                   (0.5, 0.5),
                   (0.7, 0.5),
                   (1.0, 1.0)])

x_ = np.linspace(0.0, 1.0, 100)
x = np.linspace(0.0, 1.0, 11)
f = UnivariateSpline(points[:,0], points[:, 1],k=3)

fig, ax = plt.subplots(1, 1, figsize=(5,5))
ax.scatter(points[:,0], points[:,1], s=20, zorder=3)
ax.scatter(x, f(x), s=20)
ax.plot(x_, f(x_), linewidth=0.8, color="C0")
ax.grid("both")
ax.set_title("Normalized spline non-linear growth")

#%%
# *********************************************************************************************************************
# PLOTTING SECTION
# *********************************************************************************************************************

fig, ax = plt.subplots(3, 1, figsize=(4, 7))
plt.subplots_adjust(top=0.95, left=0.15, wspace=1.05, right=0.7, bottom=0.05)
font_size = 10
highlight_step = 6
highlight_power = 25

max_ylim_node = 25
to_integer = 10  # Conversion of decimal points of the x axis to integer numbers
x_solutions_years = []
# =====================================================================================================================
# LINEAL CASE
# =====================================================================================================================
#  Load growth

# The mapper_load_growth() exists, because each cluster growth is bounded by the max and min energy consumption of the
# cluster. Remember that copula can not extrapolate.

# Count the nodes with the same number of clusters

n_clusters = scenario_generator.n_clusters
x_ = np.arange(0, 11)
labels_ = ["Commercial", "Residential", "Mixed activities"]
colors = ["C0", "C1", "C2"]

# From the real data
energy_limits = retrieve_energy_limits(scenario_generator)
energy_limits.loc["total"] = energy_limits.sum(axis=0, numeric_only=True)

# Made up by myself
energy_limits = pd.DataFrame({"type_bus": [0, 1, 2],
                              "minimums": [1.566978, 3.0, 1.212650],
                              "maximums": [15.507259, 9.076219, 12.0]})
energy_limits.set_index("type_bus", inplace=True)
energy_limits.loc["total"] = energy_limits.sum(axis=0, numeric_only=True)

# m = np.linspace(0, 1, 11)
m = np.linspace(0, 1, 1000)

ax_ = ax[0].twinx()
f, f_inv = normalize_and_inverse(energy_limits["minimums"]["total"], energy_limits["maximums"]["total"])  # From GWh to [% Energy]
g_normalized = growth_curve_normalized(curve="lineal")
# g_normalized = growth_curve_normalized(x=points[:, 0], y=points[:, 1], curve="spline")
g, g_inv = growth_curve(g_normalized, energy_limits["minimums"]["total"], energy_limits["maximums"]["total"])
x_1, y_1_kw, y_1_per = (m, g(m), f(g(m)))  # index, GWh/year, % Energy of GWh/year
ax_.plot(m * to_integer, y_1_kw, color="C3", linewidth=1.8, zorder=0)

ax2 = ax_.secondary_yaxis(1.2, functions=(f, f_inv))
x_highlighted = g_inv(np.array([highlight_power]))
x_solutions_years.append(np.round(x_highlighted*10,2))
lgt = ax_.scatter(x_highlighted * to_integer, highlight_power, s=20, color="C3", edgecolors="k", zorder=3,
                  label=r"$w_{\mathrm{A}}(l_{\mathrm{A}})=\sum_{i=1}^{3}\bar{w}_{i,\mathrm{A}}(l_{\mathrm{A}})$")
lgt_label = lgt.get_label()
ax_.hlines(y=highlight_power, xmin=x_highlighted * to_integer, xmax=1.0 * to_integer, color="C3", linewidths=0.5, linestyles="-.", alpha=0.8)
ax_.vlines(x=x_highlighted * to_integer, ymin=0, ymax=highlight_power, color="C3", linewidths=0.5, linestyles="-.", alpha=0.8)

y_lineal = []
lgds = []
lgds_label = []
for ii in range(n_clusters):
    f, f_inv = normalize_and_inverse(energy_limits["minimums"][ii], energy_limits["maximums"][ii])  # From GWh to [% Energy]
    g_normalized = growth_curve_normalized(curve="lineal")
    # g_normalized = growth_curve_normalized(x=points[:,0], y=points[:,1], curve="spline")
    g, g_inv = growth_curve(g_normalized, energy_limits["minimums"][ii], energy_limits["maximums"][ii])
    x_1, y_1_kw, y_1_per = (m, g(m), f(g(m)))  # index, GWh/year, % Energy of GWh/year
    ax[0].plot(m * to_integer, y_1_kw)
    lgx = ax[0].scatter(x_highlighted * to_integer, g(x_highlighted), s=20,
                        color=colors[ii], edgecolors="k",
                        label=r"$\bar{w}_{\mathrm{" + f"{ii + 1}" + r",\mathrm{A}}}(l_{\mathrm{A}})$")
    lgds_label.append(lgx.get_label())
    ax[0].hlines(y=g(x_highlighted), xmin=0, xmax=x_highlighted*to_integer, color=colors[ii], linewidths=0.5, linestyles="-.", alpha=0.8)

    lgds.append(lgx)
    y_lineal.append(g(x_highlighted))

ax[0].set_ylim((0,max_ylim_node))
ax_.set_ylim((energy_limits["minimums"]["total"], 40))
ax_.set_ylabel("Total grid Energy consump. [GWh/Year]")
ax_.spines['right'].set_color('red')
ax_.yaxis.label.set_color('red')
ax_.tick_params(axis='y', colors='red')

ax2.yaxis.set_major_locator(mticker.MultipleLocator(0.1))
ax2.yaxis.set_major_formatter(mticker.PercentFormatter(xmax=1.0))
ax2.set_ylabel("Annual energy\nconsumption growth [\%]", fontsize=font_size)
ax2.tick_params(axis='both', which='major', labelsize=font_size-1)
ax2.tick_params(axis='both', which='minor', labelsize=font_size-1)
ax[0].set_ylabel("Annual energy consumption\nper node [GWh/Year]")
ax[0].set_title("(a)")
lgds = [lgt] + lgds
lgds_label = [lgt_label] + lgds_label
ax[0].legend(lgds, lgds_label,
             loc="upper left",
             handletextpad=-0.1,
             handlelength=2.0)
ax[0].xaxis.set_major_locator(mticker.MultipleLocator(1.0))

# =====================================================================================================================
# SPLINE CASE
# =====================================================================================================================
#  Load growth

# The mapper_load_growth() exists, because each cluster growth is bounded by the max and min energy consumption of the
# cluster. Remember that copula can not extrapolate.

ax_ = ax[1].twinx()
f, f_inv = normalize_and_inverse(energy_limits["minimums"]["total"], energy_limits["maximums"]["total"])  # From GWh to [% Energy]
# g_normalized = growth_curve_normalized(curve="lineal")
g_normalized = growth_curve_normalized(x=points[:, 0], y=points[:, 1], curve="spline")
g, g_inv = growth_curve(g_normalized, energy_limits["minimums"]["total"], energy_limits["maximums"]["total"])
x_1, y_1_kw, y_1_per = (m, g(m), f(g(m)))  # index, GWh/year, % Energy of GWh/year
ax_.plot(m * to_integer, y_1_kw, color="C3", linewidth=1.8, zorder=0)

ax2 = ax_.secondary_yaxis(1.2, functions=(f, f_inv))
x_highlighted = g_inv(np.array([highlight_power]))
x_solutions_years.append(np.round(x_highlighted*10,2))
lgt = ax_.scatter(x_highlighted * to_integer, highlight_power, s=20, color="C3", edgecolors="k", zorder=3,
                  label=r"$w_{\mathrm{B}}(l_{\mathrm{B}})=\sum_{i=1}^{3}\bar{w}_{i,\mathrm{B}}(l_{\mathrm{B}})$")
lgt_label = lgt.get_label()
ax_.hlines(y=highlight_power, xmin=x_highlighted * to_integer, xmax=1.0 * to_integer, color="C3", linewidths=0.5, linestyles="-.", alpha=0.8)
ax_.vlines(x=x_highlighted * to_integer, ymin=0, ymax=highlight_power, color="C3", linewidths=0.5, linestyles="-.", alpha=0.8)

# Count the nodes with the same number of clusters
energy_highlighted = []
y_spline = []
lgds = []
lgds_label = []
for ii in range(n_clusters):
    f, f_inv = normalize_and_inverse(energy_limits["minimums"][ii], energy_limits["maximums"][ii])  # From GWh to [% Energy]
    # g_normalized = growth_curve_normalized(curve="lineal")
    g_normalized = growth_curve_normalized(x=points[:,0], y=points[:,1], curve="spline")
    g, g_inv = growth_curve(g_normalized, energy_limits["minimums"][ii], energy_limits["maximums"][ii])
    x_1, y_1_kw, y_1_per = (m, g(m), f(g(m)))  # index, GWh/year, % Energy of GWh/year
    ax[1].plot(m * to_integer, y_1_kw)
    lgx = ax[1].scatter(x_highlighted * to_integer, g(x_highlighted), s=20,
                        color=colors[ii], edgecolors="k", label=r"$\bar{w}_{\mathrm{" + f"{ii+1}" + r",B}}(l_{\mathrm{B}})$")
    lgds_label.append(lgx.get_label())
    ax[1].hlines(y=g(x_highlighted), xmin=0, xmax=x_highlighted * to_integer, color=colors[ii], linewidths=0.5, linestyles="-.", alpha=0.8)

    lgds.append(lgx)

    y_spline.append(g(x_highlighted))

ax[1].set_ylim((0,max_ylim_node))
ax_.set_ylim((energy_limits["minimums"]["total"], 40))
ax_.set_ylabel("Total grid Energy consump. [GWh/Year]")
ax_.spines['right'].set_color('red')
ax_.yaxis.label.set_color('red')
ax_.tick_params(axis='y', colors='red')

ax2.yaxis.set_major_locator(mticker.MultipleLocator(0.1))
ax2.yaxis.set_major_formatter(mticker.PercentFormatter(xmax=1.0))
ax2.set_ylabel("Annual energy\nconsumption growth [\%]", fontsize=font_size)
ax2.tick_params(axis='both', which='major', labelsize=font_size-1)
ax2.tick_params(axis='both', which='minor', labelsize=font_size-1)
ax[1].set_ylabel("Annual energy consumption\nper node [GWh/Year]")
ax[1].set_title("(b)")
lgds = [lgt] + lgds
lgds_label = [lgt_label] + lgds_label
ax[1].legend(lgds, lgds_label,
             loc="upper left",
             handletextpad=-0.1,
             handlelength=2.0)
ax[1].xaxis.set_major_locator(mticker.MultipleLocator(1.0))

# =====================================================================================================================
# ROOT CASE
# =====================================================================================================================
#  Load growth

# The mapper_load_growth() exists, because each cluster growth is bounded by the max and min energy consumption of the
# cluster. Remember that copula can not extrapolate.

ax_ = ax[2].twinx()
f, f_inv = normalize_and_inverse(energy_limits["minimums"]["total"], energy_limits["maximums"]["total"])  # From GWh to [% Energy]
# g_normalized = growth_curve_normalized(curve="lineal")
g_normalized = growth_curve_normalized(x=points[:, 0], y=points[:, 1], curve="root")
g, g_inv = growth_curve(g_normalized, energy_limits["minimums"]["total"], energy_limits["maximums"]["total"])
x_1, y_1_kw, y_1_per = (m, g(m), f(g(m)))  # index, GWh/year, % Energy of GWh/year
ax_.plot(m * to_integer, y_1_kw, color="C3", linewidth=1.8, zorder=0)

# ax_.arrow(x=0.9, y=0, dx=0, dy=25,
#           length_includes_head=True,
#           head_width=0.04,
#           head_length=3,
#           shape="full",
#           overhang=1,
#           color="C3")
# ax_.text(x=0.82,y=10,s=r"$\bar{\mathrm{A}}$", fontsize="x-large", color="C3")

ax2 = ax_.secondary_yaxis(1.2, functions=(f, f_inv))
x_highlighted = g_inv(np.array([highlight_power]))
x_solutions_years.append(np.round(x_highlighted*10,2))
lgt = ax_.scatter(x_highlighted * to_integer, highlight_power, s=20, color="C3", edgecolors="k", zorder=3,
                  label=r"$w_{\mathrm{C}}(l_{\mathrm{C}})=\sum_{i=1}^{3}\bar{w}_{i,\mathrm{C}}(l_{\mathrm{C}})$")
lgt_label = lgt.get_label()
ax_.hlines(y=highlight_power, xmin=x_highlighted * to_integer, xmax=1.0 * to_integer, color="C3", linewidths=0.5, linestyles="-.", alpha=0.8)
ax_.vlines(x=x_highlighted * to_integer, ymin=0, ymax=highlight_power, color="C3", linewidths=0.5, linestyles="-.", alpha=0.8)

# Count the nodes with the same number of clusters
energy_highlighted = []
y_root = []

x_arrow_position = [0.25, 0.05, 0.15]
arrow_names = ["B", "C", "D"]
lgds = []
lgds_label = []
for ii in range(n_clusters):
    f, f_inv = normalize_and_inverse(energy_limits["minimums"][ii], energy_limits["maximums"][ii])  # From GWh to [% Energy]
    # g_normalized = growth_curve_normalized(curve="lineal")
    g_normalized = growth_curve_normalized(x=points[:,0], y=points[:,1], curve="root")
    g, g_inv = growth_curve(g_normalized, energy_limits["minimums"][ii], energy_limits["maximums"][ii])
    x_1, y_1_kw, y_1_per = (m, g(m), f(g(m)))  # index, GWh/year, % Energy of GWh/year
    ax[2].plot(m * to_integer, y_1_kw, color=colors[ii])
    lgx = ax[2].scatter(x_highlighted * to_integer, g(x_highlighted), s=20,
                        color=colors[ii], edgecolors="k",
                        label=r"$\bar{w}_{\mathrm{" + f"{ii+1}" + r",\mathrm{C}}}(l_{\mathrm{C}})$" )
    lgds_label.append(lgx.get_label())
    ax[2].hlines(y=g(x_highlighted), xmin=0, xmax=x_highlighted * to_integer, color=colors[ii], linewidths=0.5, linestyles="-.", alpha=0.8)

    lgds.append(lgx)
    # ax[2].arrow(x=x_arrow_position[ii], y=0, dx=0, dy=g(x_highlighted)[0],
    #             length_includes_head=True,
    #             head_width=0.04,
    #             head_length=1.5,
    #             shape="full",
    #             overhang=1,
    #             color=colors[ii])
    # ax[2].text(x=x_arrow_position[ii] + 0.0125, y=1.25,
    #            s=r"$\bar{\mathrm{"+f"{arrow_names[ii]}"+ "}}$", fontsize="x-large", color=colors[ii])
    y_root.append(g(x_highlighted))

ax[2].set_ylim((0,max_ylim_node))
ax_.set_ylim((energy_limits["minimums"]["total"], 40))
ax_.set_ylabel("Total grid Energy consump. [GWh/Year]")
ax_.spines['right'].set_color('red')
ax_.yaxis.label.set_color('red')
ax_.tick_params(axis='y', colors='red')

ax2.yaxis.set_major_locator(mticker.MultipleLocator(0.1))
ax2.yaxis.set_major_formatter(mticker.PercentFormatter(xmax=1.0))
ax2.set_ylabel("Annual energy\nconsumption growth [\%]", fontsize=font_size)
ax2.tick_params(axis='both', which='major', labelsize=font_size-1)
ax2.tick_params(axis='both', which='minor', labelsize=font_size-1)

ax[2].set_ylabel("Annual energy consumption\nper node [GWh/Year]")
ax[2].set_title("(c)")
lgds = [lgt] + lgds
lgds_label = [lgt_label] + lgds_label
ax[2].legend(lgds, lgds_label,
             loc="upper left",
             handletextpad=-0.1,
             handlelength=2.0)
ax[2].xaxis.set_major_locator(mticker.MultipleLocator(1.0))
ax[2].set_xlabel("Step increment ($l$) - [years]")

comparison = pd.DataFrame(np.concatenate([y_lineal, y_root, y_spline], axis=1).T,
                          columns=["w1", "w2", "w3"],
                          index=["lineal", "root", "spline"])
print(comparison)
print(f"Years: {x_solutions_years}")
plt.savefig(".\path_growths\paths_appendix.pdf", dpi=700, bbox_inches='tight' )
#%%


import threading
from collections import deque
import time

class BusyWaitingThread(threading.Thread):
	def __init__(self):
		self._running = False
		self._tasks = deque([])
		threading.Thread.__init__(self)

	def run(self):
		self._running = True
		while self._running:
			if len(self._tasks) == 0:
				time.sleep(0.001)
				continue
			taskFn, afterTime = self._tasks[0]
			if time.time() > afterTime:
				# print("busyWaitingThread timeDiff (ms)", (time.time() - afterTime) * 1000)
				taskFn()
				self._tasks.popleft()

	def doTaskAfter(self, taskFn, afterTime):
		# Assume afterTime is always later than all existing tasks.
		self._tasks.append((taskFn, afterTime))

	def stop(self):
		self._running = False


#!/usr/bin/python
import random
import copy
from collections import defaultdict

class DP(object):
    '''Class for Davis-Putnam solver.
    '''

    def __init__(self, file):
        self.file = file
        self.split = 0
        self.count = 0

    def split_choice(self, clauses):
        '''Select a heuristic to split.

        Arguments:
            clauses {list} -- list of clauses

        Returns:
            int -- variable to split
        '''

        if self.split == 1:
            return self.random_split(clauses)
        elif self.split == 2:
            return self.JW_det_split(clauses)
        elif self.split == 3:
            return self.JW_prob_split(clauses)
        elif self.split == 4:
            return self.DLIS_det_split(clauses)
        elif self.split == 5:
            return self.DLIS_prob_split(clauses)

    def solver(self, clauses):
        '''Main method of solver.

        Arguments:
            clauses {list} -- list of clauses

        Returns:
            dict -- dictionary of variables with assigned values
        '''

        # print('|START count:', self.count)
        # print('start:', clauses)
        clauses = self.pure_literals(clauses)
        # print('after pure:', clauses)
        clauses = self.unit_clauses(clauses)
        # print('after unit:', clauses)
        if [] in clauses:
            # print('false')
            return False
        if len(clauses) == 0:
            # print('success!')
            return self.vars
        split_var = self.split_choice(clauses)
        self.count += 1
        # print(split_var)
        tmp = copy.deepcopy(clauses)
        assignment = self.solver(self.remove_clauses(split_var, clauses))
        if assignment is False:
            # print('backtracking...')
            self.count += 1
            clauses = copy.deepcopy(tmp)
            assignment = self.solver(self.remove_clauses(-split_var, clauses))
        if assignment is False:
            return False
        return self.vars

    def random_split(self, clauses):
        '''Random splitting heuristic.

        Arguments:
            clauses {list} -- list of clauses

        Returns:
            int -- variable to split
        '''

        clause = random.choice(clauses)
        split = random.choice(clause)
        return split

    def remove_clauses(self, variable, clauses):
        '''Update the list of clauses with the given variable assigned.

        Arguments:
            variable {int} -- variable with assgined value
            clauses {list} -- list of clauses

        Returns:
            list -- updated list of clauses
        '''

        new_clauses = []
        if variable >= 0:
            self.vars[variable] = True
        else:
            self.vars[abs(variable)] = False
        for clause in clauses:
            if variable in clause:
                continue
            else:
                if -variable in clause:
                    clause.remove(-variable)
                new_clauses.append(clause)
        return new_clauses

    def remove_clauses_testing_only(self, variable, clauses):
        '''Update the list of clauses with the given variable assigned.

        Arguments:
            variable {int} -- variable with assgined value
            clauses {list} -- list of clauses

        Returns:
            list -- updated list of clauses
        '''

        print('variable:', variable)
        print('number of clauses:', len(clauses))
        new_clauses = []
        if variable >= 0:
            self.vars[variable] = True
        else:
            self.vars[abs(variable)] = False
        for clause in clauses:
            if variable in clause:
                continue
            else:
                if -variable in clause:
                    clause.remove(-variable)
                new_clauses.append(clause)
        return new_clauses

    def read(self):
        '''Method for reading the clauses from the input file.

        Returns:
            list -- list of clauses
        '''

        # Initialize clauses list.
        clauses = []

        # Initialize variables.
        vars_tmp = set()

        # Start reading from the file.
        with open(self.file, 'r') as input_file:
            for line in input_file:
                parsed = line.split()

                # Check whether it is valid line or supplementary line.
                if not parsed or parsed[0] == 'p' or parsed[0] == 'c':
                    continue
                else:
                    eff_parsed = parsed[:-1]
                    clause = set()
                    for lit in eff_parsed:
                        lit = int(lit)
                        clause.add(lit)

                        # Collect variable.
                        abs_lit = abs(lit)
                        vars_tmp.add(abs_lit)
                    clauses.append(list(clause))

        # Initialize all collected variables, e.g. {'115': [False] ...} - where [truth_val]
        self.vars = dict.fromkeys(vars_tmp, False)
        return clauses

    def tautology(self, clauses):
        '''Check and remove tautology from the list of clauses.

        Returns:
            list -- list of clauses
        '''

        new_clauses = []
        check = 1
        for clause in clauses:
            for lit in clause:
                if -lit in clause:
                    check = 0
                    break
            if check == 1:
                new_clauses.append(clause)
            else:
                check = 1
        return new_clauses

    def pure_literals(self, clauses):
        '''Collect and remove the pure literals from the list of clauses.

        Returns:
            list -- list of clauses
        '''

        p_lits = set()
        non_p_lits = set()
        for clause in clauses:
            for lit in clause:
                neg_lit = -lit
                abs_lit = abs(lit)
                if neg_lit not in p_lits:
                    if abs_lit not in non_p_lits:
                        p_lits.add(lit)
                else:
                    p_lits.remove(neg_lit)
                    non_p_lits.add(abs_lit)
        for lit in p_lits:
            clauses = self.remove_clauses(lit, clauses)
        return clauses

    def unit_clauses(self, clauses):
        '''Collect and remove unit clauses from the list of clauses.

        Returns:
            list -- list of clauses
        '''

        unit_var = set()
        for clause in clauses:
            if len(clause) == 1:
                unit_var.add(clause[0])
        while len(unit_var) > 0:
            for unit in unit_var:
                clauses = self.remove_clauses(unit, clauses)
            unit_var = set()
            clauses = self.unit_clauses(clauses)
        return clauses

    def JW_det_split(self, clauses):
        '''Use deterministic Jeroslow-Wang heuristic to split variable.

        Arguments:
            clauses {list} -- list of clauses

        Returns:
            int -- selected variable to split
        '''

        J = defaultdict(int)
        for clause in clauses:
            clause_len = len(clause)
            for lit in clause:
                J[lit] += 2 ** (-clause_len)

        max_pair = [-1, 0]
        for k in J.keys():
            sum_J = J[k] + J[-k]
            if sum_J > max_pair[1] and max_pair[0] != -k:
                max_pair = [k, sum_J]

        split = abs(max_pair[0])
        if J[split] >= J[-split]:
            return split
        else:
            return -split

    def JW_prob_split(self, clauses):
        '''Use probabilistic Jeroslow-Wang heuristic to split variable.

        Arguments:
            clauses {list} -- list of clauses

        Returns:
            int -- selected variable to split
        '''

        J = defaultdict(int)
        for clause in clauses:
            clause_len = len(clause)
            for lit in clause:
                J[lit] += 2 ** (-clause_len)

        choices = []
        vals = []
        for k, v in J.items():
            lit = abs(k)
            if lit not in choices:
                choices.append(lit)
                vals.append(J[k] + J[-k])

        split = random.choices(choices, weights=vals, k=1)
        split = split[0]

        split = random.choices([split, -split], weights=[J[split], J[-split]], k=1)
        split = split[0]
        return split

    def DLIS_det_split(self, clauses):
        '''Use deterministic DLIS heuristic to split variable.

        Arguments:
            clauses {list} -- list of clauses

        Returns:
            int -- selected variable to split
        '''

        C_p = defaultdict(int)
        C_n = defaultdict(int)
        for clause in clauses:
            for lit in clause:
                if lit > 0:
                    C_p[lit] += 1
                else:
                    C_n[lit] += 1
        max_pair_p = [0, -1]
        for k, v in C_p.items():
            if v > max_pair_p[1]:
                max_pair_p = [k, v]

        max_pair_n = [0, -1]
        for k, v in C_n.items():
            if v > max_pair_n[1]:
                max_pair_n = [k, v]

        if max_pair_p[1] > max_pair_n[1]:
            return max_pair_p[0]
        else:
            return max_pair_n[0]

    def DLIS_prob_split(self, clauses):
        '''Use probabilistic DLIS heuristic to split variable.

        Arguments:
            clauses {list} -- list of clauses

        Returns:
            int -- selected variable to split
        '''

        C_p = defaultdict(int)
        C_n = defaultdict(int)
        for clause in clauses:
            for lit in clause:
                if lit > 0:
                    C_p[lit] += 1
                else:
                    C_n[lit] += 1

        choices_p = []
        weights_p = []
        for k, v in C_p.items():
            choices_p.append(k)
            weights_p.append(v)

        choices_n = []
        weights_n = []
        for k, v in C_n.items():
            choices_n.append(k)
            weights_n.append(v)

        choice_p = random.choices(choices_p, weights=weights_p, k=1)
        choice_p = choice_p[0]
        val_p = C_p[choice_p]

        choice_n = random.choices(choices_n, weights=weights_n, k=1)
        choice_n = choice_n[0]
        val_n = C_n[choice_n]

        split = random.choices([choice_p, choice_n], weights=[val_p, val_n], k=1)
        split = split[0]
        return split

    def output_results(self, vars=None):
        '''Method for outputting the results into input_filename.out.

        Keyword Arguments:
            vars {dict} -- dictionary to store the variables with their assignments (default: {None})
        '''

        input_file_name = self.file.split('/')
        input_file_name = input_file_name[-1]
        output_file = input_file_name[:-4] + '.out'
        if vars is None:
            with open(output_file, 'w') as output:
                output.write('')
        else:
            assignments = []
            for k, v in vars.items():
                if v:
                    assignments.append(str(k) + ' 0\n')
                else:
                    assignments.append(str(-k) + ' 0\n')
            with open(output_file, 'w') as output:
                output.write('p cnf {} {}\n'.format(len(vars), len(vars)))
                output.writelines(assignments)


from datetime import datetime

from sqlalchemy.dialects.postgresql import JSONB, UUID
from sqlalchemy_utils import EmailType, generic_repr

from ...application import db

db.JSONB, db.UUID, db.EmailType = (JSONB, UUID, EmailType)

@generic_repr
class Base(db.Model):
    __abstract__ = True
    created_on = db.Column(
        db.DateTime, default=datetime.utcnow, server_default=db.func.now()
    )
    updated_on = db.Column(
        db.DateTime,
        default=datetime.utcnow,
        onupdate=datetime.utcnow,
        server_default=db.func.now(),
    )
    id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)


"""
  Name     : c12_36_terminal_stock_price_distribution.py
  Book     : Python for Finance (2nd ed.)
  Publisher: Packt Publishing Ltd.
  Author   : Yuxing Yan
  Date     : 6/6/2017
  email    : yany@canisius.edu
             paulyxy@hotmail.com
"""
import scipy as sp
import matplotlib.pyplot as plt
from scipy import zeros, sqrt, shape
#input area
S0 = 9.15               # stock price at time zero
T =1.                   # years
n_steps=100.            # number of steps
mu =0.15                # expected annual return
sigma = 0.2             # volatility (annual)
sp.random.seed(12345)   # fix those random numbers
n_simulation = 1000     # number of simulation
dt =T/n_steps
#
S = zeros([n_simulation], dtype=float)
x = range(0, int(n_steps), 1)
for j in range(0, n_simulation):
    tt=S0
    for i in x[:-1]:
        e=sp.random.normal()
        tt+=tt*(mu-0.5*pow(sigma,2))*dt+sigma*tt*sqrt(dt)*e;
        S[j]=tt
#
plt.title('Histogram of terminal price')
plt.ylabel('Number of frequencies')
plt.xlabel('Terminal price')
plt.figtext(0.5,0.8,'S0='+str(S0)+',mu='+str(mu)+',sigma='+str(sigma))
plt.figtext(0.5,0.76,'T='+str(T)+', steps='+str(int(n_steps)))
plt.figtext(0.5,0.72,'Number of terminal prices='+str(int(n_simulation)))
plt.hist(S)
plt.show()


import  pandas as  pd
import  numpy as np
from sklearn.impute import SimpleImputer
df= pd.read_csv('categorical_data.csv')
imputer = SimpleImputer(missing_values=np.NaN, strategy='mean')
"""SimpleImputer nhận hai đối số như giá trị thiếu và chiến lược.
Phương thức fit_transform được gọi trên phiên bản của SimpleImputer để xác định các giá trị còn thiếu."""
df.age = imputer.fit_transform(df['age'].values.reshape(-1,1))[:,0]
"""tìm kiếm và thay thế các giá trị còn thiếu bằng giá trị trung bình của cột age"""
df.salary = imputer.fit_transform(df['salary'].values.reshape(-1,1))[:,0]
"""tương tự với cột age"""
print(df)
print(df)
print(df.mean())
"""hiển thị ra giá trị trung bình của các cột"""
print(df.fillna(df.mean()))
"""thay thế giá trị NaN bằng giá trị trung bình của cột """
b = df['age'].mean()
print(b)
"""em thử nhưng không làm ra được ý tính gtri TB bằng cộng tay ạ """


import torch
import pandas as pd

class CSVDataset(torch.utils.data.Dataset):

    def __init__(self, x_csv_path, window_length = 50):

        # load csv file as dataframe

        self.x = pd.read_csv(x_csv_path,header = None)

        # specify how many samples in a window

        self.window_length = window_length

    def __len__(self): # number of windows

        return int(len(self.x) / self.window_length)

    def __getitem__(self,idx):

        # get sample numbers for window start and end

        start = idx*self.window_length
        end = start + self.window_length

        # extract window and convert to NumPy array

        window = self.x.iloc[start:end,2].to_numpy(copy = True)

        # convert window to torch column tensor

        window = torch.from_numpy(window)

        # convert to one-hot encoding

        window = torch.nn.functional.one_hot(window - 1).to(torch.float)

        return window

if __name__ == '__main__':

    path = '../data/train.csv'
    dataset = CSVDataset(path)

    x = dataset[len(dataset)-1]


from django.urls import path
from rest_framework_nested import routers
from . import views
from core.views import (
    ApartmentImageViewSet,
    ContractViewSet,
    BillViewSet,
    RoomImageViewSet,
    RoomViewSet,
)

app_name = "owner"

router = routers.DefaultRouter()
router.register("owner-apartments", views.OwnerApartmentViewSet, basename="apartments")
router.register("owner-rooms", views.OwnerRoomViewSet, basename="rooms")
router.register("owner-contarcts", ContractViewSet, basename="contracts")
router.register("owner-bills", BillViewSet, basename="bills")

urlpatterns = [
    path(
        "owner-apartments/<int:pk>/upload_image/",
        views.OwnerApartmentViewSet.as_view({"patch": "upload_image"}),
        name="apartment-upload-image",
    ),
    path(
        "owner-apartments/<int:apartment_id>/rooms/",
        views.OwnerRoomViewSet.as_view(
            {
                "get": "list",
                "put": "update",
                "delete": "destroy",
                "post": "create",
                "patch": "partial_update",
            }
        ),
        name="rooms",
    ),
    path(
        "owner-apartments/<int:apartment_id>/rooms/",
        views.OwnerRoomViewSet.as_view(
            {
                "get": "list",
                "put": "update",
                "delete": "destroy",
                "post": "create",
                "patch": "partial_update",
            }
        ),
        name="owner-room-detail",
    ),
    path(
        "owner-apartments/<int:apartment_id>/room/<int:pk>/",
        RoomViewSet.as_view(
            {
                "get": "retrieve",
                "put": "update",
                "delete": "destroy",
                "post": "create_contract",
                "patch": "partial_update",
            }
        ),
        name="room-detail",
    ),
    path(
        "owner-apartments/<int:apartment_id>/contracts/<int:pk>/",
        ContractViewSet.as_view(
            {
                "get": "retrieve",
                "put": "update",
                "patch": "partial_update",
                "delete": "destroy",
                "post": "create",
            }
        ),
        name="contract_detail",
    ),
    path(
        "owner-apartments/<int:apartment_id>/room/<int:room_id>/contracts/",
        ContractViewSet.as_view(
            {
                "get": "list",
                "post": "create",
            }
        ),
        name="contracts",
    ),
    path(
        "owner-apartments/<int:apartment_id>/room/<int:room_id>/contracts/<int:pk>/",
        ContractViewSet.as_view(
            {
                "get": "retrieve",
                "put": "update",
                "patch": "partial_update",
                "delete": "destroy",
                "post": "create",
            }
        ),
        name="contract_detail",
    ),
    path(
        "owner-apartments/<int:apartment_id>/bills/<int:pk>/",
        BillViewSet.as_view(
            {
                "get": "retrieve",
                "put": "update",
                "patch": "partial_update",
                "delete": "destroy",
                "post": "create",
            }
        ),
        name="bill_detail",
    ),
    path(
        "owner-apartments/<int:apartment_id>/bills/<int:pk>/upload_file/",
        BillViewSet.as_view(
            {
                "patch": "upload_file",
                "post": "upload_fle",
            }
        ),
        name="bill-upload-file",
    ),
    path(
        "owner-apartments/<int:apartment_id>/bills/<int:bill_id>/download/",
        BillViewSet.as_view({"get": "download"}),
        name="bill-download-file",
    ),
    path(
        "owner-rooms/<int:room_id>/contracts/<int:pk>/",
        ContractViewSet.as_view(
            {
                "get": "retrieve",
                "put": "update",
                "patch": "partial_update",
                "delete": "destroy",
                "post": "create",
            }
        ),
        name="contract_detail",
    ),
    path(
        "owner-rooms/<int:pk>/create_contract/",
        ContractViewSet.as_view(
            {
                "get": "retrieve",
                "put": "update",
                "patch": "partial_update",
                "delete": "destroy",
                "post": "create",
            }
        ),
        name="create_contract",
    ),
    path(
        "owner-apartments/<int:apartment_id>/bills/<int:pk>/delete-file/",
        BillViewSet.as_view({"delete": "delete_file"}),
        name="delete_bill_file",
    ),
    path(
        "owner-apartments/<int:apartment_id>/room/<int:room_id>/contracts/<int:pk>/delete-file/",
        ContractViewSet.as_view({"delete": "delete_file"}),
        name="delete_contract_file",
    ),
    path(
        "owner-apartments/<int:apartment_id>/images/",
        ApartmentImageViewSet.as_view({"get": "list"}),
        name="apartment_image_list",
    ),
    path(
        "owner-apartments/<int:apartment_id>/images/<int:pk>/",
        ApartmentImageViewSet.as_view({"get": "retrieve", "delete": "destroy"}),
        name="apartment_image_detail",
    ),
    path(
        "owner-rooms/<int:room_id>/images/",
        RoomImageViewSet.as_view({"get": "list"}),
        name="room_image_list",
    ),
    path(
        "owner-rooms/<int:room_id>/images/<int:pk>/",
        RoomImageViewSet.as_view({"get": "retrieve", "delete": "destroy"}),
        name="room_image_detail",
    ),
] + router.urls