import pygame
import os
from math import cos, radians
from pictures import cardPictures, chipsPictures
from button import button_class
from Service import Service
from ChipClasses import Chips

service = Service()

os.environ['SDL_VIDEO_CENTERED'] = '1'

pygame.init()

screenWidth = 1200
screenHeight = 650

screen = pygame.display.set_mode((screenWidth, screenHeight))

pygame.display.set_caption("Blackjack")
icon = pygame.image.load("blackjack_icon.png")
pygame.display.set_icon(icon)

green = (46, 84, 44)
blue = (43, 50, 255)
grey = (130, 130, 130)
white = (255, 255, 255)
black = (0, 0, 0)
yellow = (255, 255, 0)

chipHeight = chipsPictures.blackChip.get_height()
chipWidth = chipsPictures.blackChip.get_width()
buttonSpace = screenWidth / 240
buttonHeight = chipHeight
buttonWidth = (screenWidth - (chipWidth + buttonSpace) * 6 - buttonSpace * 8) / 7  # 100 #75

clearBtn = button_class(grey, screenWidth - (buttonWidth + buttonSpace) * 7 - (chipWidth + buttonSpace) * 6,
                        screenHeight - (chipHeight + buttonSpace), buttonWidth, buttonHeight, True, "Clear")
copyBtn = button_class(grey, screenWidth - (buttonWidth + buttonSpace) * 6 - (chipWidth + buttonSpace) * 6,
                       screenHeight - (chipHeight + buttonSpace), buttonWidth, buttonHeight, True, "Copy")
bet100Btn = button_class(green, screenWidth - (buttonWidth + buttonSpace) * 5 - (chipWidth + buttonSpace) * 6,
                         screenHeight - (chipHeight + buttonSpace), chipWidth, chipHeight, True, "")
bet25Btn = button_class(green, screenWidth - (buttonWidth + buttonSpace) * 5 - (chipWidth + buttonSpace) * 5,
                        screenHeight - (chipHeight + buttonSpace), chipWidth, chipHeight, True, "")
bet10Btn = button_class(green, screenWidth - (buttonWidth + buttonSpace) * 5 - (chipWidth + buttonSpace) * 4,
                        screenHeight - (chipHeight + buttonSpace), chipWidth, chipHeight, True, "")
bet5Btn = button_class(green, screenWidth - (buttonWidth + buttonSpace) * 5 - (chipWidth + buttonSpace) * 3,
                       screenHeight - (chipHeight + buttonSpace), chipWidth, chipHeight, True, "")
bet1Btn = button_class(green, screenWidth - (buttonWidth + buttonSpace) * 5 - (chipWidth + buttonSpace) * 2,
                       screenHeight - (chipHeight + buttonSpace), chipWidth, chipHeight, True, "")
bet0point1Btn = button_class(green, screenWidth - (buttonWidth + buttonSpace) * 5 - (chipWidth + buttonSpace) * 1,
                             screenHeight - (buttonHeight + buttonSpace), chipWidth, chipHeight, True, "")
dealBtn = button_class(blue, screenWidth - (buttonWidth + buttonSpace) * 5, screenHeight - (buttonHeight + buttonSpace),
                       buttonWidth, buttonHeight, True, "Deal")
hitBtn = button_class(grey, screenWidth - (buttonWidth + buttonSpace) * 4, screenHeight - (buttonHeight + buttonSpace),
                      buttonWidth, buttonHeight, False, "Hit")
standBtn = button_class(grey, screenWidth - (buttonWidth + buttonSpace) * 3,
                        screenHeight - (buttonHeight + buttonSpace), buttonWidth, buttonHeight, False, "Stand")
doubleBtn = button_class(grey, screenWidth - (buttonWidth + buttonSpace) * 2,
                         screenHeight - (buttonHeight + buttonSpace), buttonWidth, buttonHeight, False, "Double")
splitBtn = button_class(grey, screenWidth - (buttonWidth + buttonSpace) * 1,
                        screenHeight - (buttonHeight + buttonSpace), buttonWidth, buttonHeight, False, "Split")
yesBtn = button_class(blue, screenWidth / 2 - 150, screenHeight / 2, 100, 50, False, "Yes")
noBtn = button_class(blue, screenWidth / 2 + 50, screenHeight / 2, 100, 50, False, "No")

running = True
cardsMoving = False
askingForInsurance = False

cardWidth = cardPictures.cardBack.get_width()
cardHalfWidth = cardWidth / 2
cardHeight = cardPictures.cardBack.get_height()
cardHalfHeight = cardHeight / 2
cardDisplacemnet = 20  # 25

# TODO: cardDisplacement så att den ändras för spelaren eller annan lösning så korten aldrig krockar med dealerns kort

# Some variables to show-off the card
d = 1  # Direction to spin
speed = 4  # Spin speed
a = 0  # Angle to show
turns = 180 / (d * speed)

cardStartX = screenWidth - cardHalfWidth - 25
cardStartY = cardHalfHeight + 25
# cardStartX = 1117
# cardStartY = 97.5

cardPosX = screenWidth / 2
cardPosY = screenHeight - 275  # 525

cardX = cardStartX
cardY = cardStartY

chipPosX = screenWidth / 2 - chipWidth / 2
chipPosY = screenHeight - 150  # 675

chipsTotalScoreX = buttonSpace
chipsTotalScoreY = screenHeight - (buttonHeight + buttonSpace) * 2  # screenHeight - (buttonHeight + buttonSpace)
chipsTotalScoreWidth = screenWidth - (buttonWidth + buttonSpace) * 5 - (
            chipWidth + buttonSpace) * 6 - buttonSpace * 2  # screenWidth - (buttonWidth + buttonSpace) * 7 - (chipWidth + buttonSpace) * 6 - buttonSpace * 2
chipsTotalScoreHeight = buttonHeight

askForInsuranceWindowWidth = int(screenWidth / 3)
askForInsuranceWindowHeight = int(screenHeight * 4 / 13)
askForInsuranceWindowX = (screenWidth - askForInsuranceWindowWidth) / 2
askForInsuranceWindowY = (screenHeight - askForInsuranceWindowHeight) / 2

dealerSpacedCardsLimit = 5

fontScore = pygame.font.SysFont("Comicsans", 100)
fontChips = pygame.font.SysFont("Comicsans", 40)
fontWinner = pygame.font.SysFont("Comicsans", 60)
fontBet = pygame.font.SysFont("Comicsans", 30)

#TODO: Tjock i andra (vänstra) högen när spiltat inte automatisk omstart
#TODO: avsluta spelet också efter

def drawCard(x, y, card, angle):
    cardSurface = pygame.Surface((cardWidth, cardHeight))  # creates surface

    tx, ty = x - cardHalfWidth, y - cardHalfHeight  # Top-left co-ordinates
    w = cardWidth  # Width of card
    cardSurface.blit(card, (0, 0))  # Blits the front of the card (white side)

    if angle < 90:  # If the card is still turned over (or the back is still visible)
        cardSurface.blit(cardPictures.cardBack, (0, 0))  # Draw back of card (red side)

        if angle > 0:  # If not completely faced down
            # rotate
            w = cos(radians(angle)) * cardWidth  # Work out the new width based on the angle and original width
            cardSurface = pygame.transform.scale(cardSurface, (int(w), cardHeight))  # Scale the width

    elif angle == 90:  # If exactly horizontal
        cardSurface.blit(cardPictures.cardBack, (0, 0))
        w = 1  # Display the back in a 1 pixel width surface
        cardSurface = pygame.transform.scale(cardSurface, (int(w), cardHeight))

    elif angle < 180:  # Same as before
        # rotate
        w = cos(radians(180 - angle)) * cardWidth
        cardSurface = pygame.transform.scale(cardSurface, (int(w), cardHeight))

    px = x - int(
        w / 2)  # Works out the new place-x coordinate based on the new width (ensuring the centre point remains the same regardless of width)
    screen.blit(cardSurface, (int(px), int(ty)))

def message_to_screen(msg, color, font, x, y):
    screen_text = font.render(str(msg), True, color)

    if font == fontBet:
        x -= screen_text.get_width()

    else:
        x -= screen_text.get_width() / 2

    y -= screen_text.get_height() / 2

    screen.blit(screen_text, (x, y))

def blitWinnerMsg():
    winner = service.checkForWinner()

    for i in range(len(winner)):
        if i == 0:
            x = 450
        else:
            x = 700

        if winner[i] == 0:
            message_to_screen("Blackjack!", white, fontWinner, x, 200)
        elif winner[i] == 1:
            message_to_screen("You win!", white, fontWinner, x, 200)
        elif winner[i] == 2:
            message_to_screen("Tie!", white, fontWinner, x, 200)
        elif winner[i] == 3:
            message_to_screen("Dealer win!", white, fontWinner, x, 200)

def updateScore():
    message_to_screen(service.getDealerScore(), white, fontScore, 100, cardStartY)
    message_to_screen(service.getPlayerScore(), white, fontScore, 100, cardPosY)
    if service.getPlayerAmountOfCards() >= 1 and service.getPlayerSplitAmountOfCards() >= 1:
        message_to_screen(service.getPlayerSplitScore(), white, fontScore, 1000, cardPosY)

def updateChips():
    pygame.draw.rect(screen, grey,
                     (chipsTotalScoreX - 2, chipsTotalScoreY - 2, chipsTotalScoreWidth + 4, chipsTotalScoreHeight + 4))
    pygame.draw.rect(screen, black, (chipsTotalScoreX, chipsTotalScoreY, chipsTotalScoreWidth, chipsTotalScoreHeight))

    msg = "{chips:.2f} $"

    message_to_screen(msg.format(chips=service.getPlayerChips()), yellow, fontChips,
                      chipsTotalScoreX + chipsTotalScoreWidth / 2, chipsTotalScoreY + chipsTotalScoreHeight / 2)

def turnBtnOff(btn):
    btn.color = grey
    btn.enabled = False

def turnBtnOn(btn):
    btn.color = blue
    btn.enabled = True

def adjustAngle(a, d, i):
    a += d * speed * i  # Increases/Decreases angle
    # if a >= 180:  # If fully revealed
    #    a = 180
    #    d = -1  # Switch direction
    # elif a <= 0:  # If fully turned-over
    #    a = 0
    #    d = 1  # Switch direction

    return a

def updateBtns():
    if service.isAbleToDeal() is True:
        turnBtnOn(dealBtn)
    else:
        turnBtnOff(dealBtn)

    if service.isAbleToSplit() is True:
        turnBtnOn(splitBtn)
    else:
        turnBtnOff(splitBtn)

    if service.isAbleToDouble() is True:
        turnBtnOn(doubleBtn)
    else:
        turnBtnOff(doubleBtn)

    if service.isAbleToHitOrStand() is True:
        turnBtnOn(hitBtn)
        turnBtnOn(standBtn)
    else:
        turnBtnOff(hitBtn)
        turnBtnOff(standBtn)

    if service.isHandActive() is True:
        bet100Btn.enabled = False
        bet25Btn.enabled = False
        bet10Btn.enabled = False
        bet5Btn.enabled = False
        bet1Btn.enabled = False
        bet0point1Btn.enabled = False
    else:
        bet100Btn.enabled = True
        bet25Btn.enabled = True
        bet10Btn.enabled = True
        bet5Btn.enabled = True
        bet1Btn.enabled = True
        bet0point1Btn.enabled = True

    if service.isAbleToClearBet() is True:
        turnBtnOn(clearBtn)
    else:
        turnBtnOff(clearBtn)

    if service.isAbleToCopyBet() is True:
        turnBtnOn(copyBtn)
    else:
        turnBtnOff(copyBtn)

    clearBtn.draw(screen, black)
    copyBtn.draw(screen, black)
    dealBtn.draw(screen, black)
    hitBtn.draw(screen, black)
    standBtn.draw(screen, black)
    doubleBtn.draw(screen, black)
    splitBtn.draw(screen, black)

    screen.blit(Chips.chip100.img, (screenWidth - (buttonWidth + buttonSpace) * 5 - (chipWidth + buttonSpace) * 6,
                                    screenHeight - (chipHeight + buttonSpace)))
    screen.blit(Chips.chip25.img, (screenWidth - (buttonWidth + buttonSpace) * 5 - (chipWidth + buttonSpace) * 5,
                                   screenHeight - (chipHeight + buttonSpace)))
    screen.blit(Chips.chip10.img, (screenWidth - (buttonWidth + buttonSpace) * 5 - (chipWidth + buttonSpace) * 4,
                                   screenHeight - (chipHeight + buttonSpace)))
    screen.blit(Chips.chip5.img, (screenWidth - (buttonWidth + buttonSpace) * 5 - (chipWidth + buttonSpace) * 3,
                                  screenHeight - (chipHeight + buttonSpace)))
    screen.blit(Chips.chip1.img, (screenWidth - (buttonWidth + buttonSpace) * 5 - (chipWidth + buttonSpace) * 2,
                                  screenHeight - (chipHeight + buttonSpace)))
    screen.blit(Chips.chip0point1.img, (screenWidth - (buttonWidth + buttonSpace) * 5 - (chipWidth + buttonSpace) * 1,
                                        screenHeight - (chipHeight + buttonSpace)))

def moveCards(i):
    for j in range(service.dealer.getAmountOfCards()):
        cardX = int(cardPosX - (cardWidth + cardDisplacemnet + cardHalfWidth) + (cardWidth + cardDisplacemnet) * j)

        change = (cardX - (
            int(cardPosX - (cardWidth + cardDisplacemnet + cardHalfWidth) + cardDisplacemnet * j))) / turns

        cardX -= change * i
        screen.blit(service.dealer.getPile()[j].img, (int(cardX), int(cardStartY - cardHalfHeight)))

def markActivePile():
    if cardsMoving == False:
        if service.playerHasSplit() == False:
            amount = service.getPlayerAmountOfCards()
            changeX = 0
        elif service.playerSplitStand() == False:
            amount = service.getPlayerSplitAmountOfCards()
            changeX = 180
        else:
            amount = service.getPlayerAmountOfCards()
            changeX = -180

        for i in range(amount):
            screen.blit(cardPictures.glow, (int(cardPosX - cardHalfWidth + changeX - 10 + cardDisplacemnet * i),
                                            int(cardPosY - cardHalfHeight - 10 - cardDisplacemnet * i)))

def blitPlayerCards():
    #print(cardsMoving)
    for i in range(service.getPlayerAmountOfCards()):
        if service.playerHasSplit() == False and service.getPlayerSplitAmountOfCards() != 1:
            screen.blit(service.getPlayerPile()[i].img, (int(cardPosX - cardHalfWidth + cardDisplacemnet * i),
                                                  int(cardPosY - cardHalfHeight - cardDisplacemnet * i)))
        elif service.playerHasSplit() == True and service.getPlayerAmountOfCards() >= 1 and service.getPlayerSplitAmountOfCards() >= 1 and cardsMoving == False:
            for j in range(service.getPlayerAmountOfCards()):
                screen.blit(service.getPlayerPile()[j].img, (int(cardPosX - cardHalfWidth - 180 + cardDisplacemnet * j),
                                                      int(cardPosY - cardHalfHeight - cardDisplacemnet * j)))
            for k in range(service.getPlayerSplitAmountOfCards()):
                screen.blit(service.getPlayerSplitPile()[k].img, (int(cardPosX - cardHalfWidth + 180 + cardDisplacemnet * k),
                                                           int(cardPosY - cardHalfHeight - cardDisplacemnet * k)))

def blitDealerCards():
    for i in range(service.dealer.getAmountOfCards()):
        if service.dealer.getAmountOfCards() > dealerSpacedCardsLimit:
            screen.blit(service.dealer.getPile()[i].img, (
            int(cardPosX - (cardWidth + cardDisplacemnet + cardHalfWidth) + cardDisplacemnet * i),
            int(cardStartY - cardHalfHeight)))
        elif service.dealer.getAmountOfCards() < dealerSpacedCardsLimit or service.dealer.getAmountOfCards() == dealerSpacedCardsLimit and service.dealer.getScore() >= 17:
            screen.blit(service.dealer.getPile()[i].img, (
            int(cardPosX - (cardWidth + cardDisplacemnet + cardHalfWidth) + (cardWidth + cardDisplacemnet) * i),
            int(cardStartY - cardHalfHeight)))

    if service.dealer.faceDownCards == 1:
        screen.blit(cardPictures.cardBack, (int(cardPosX - cardHalfWidth), int(cardStartY - cardHalfHeight)))

def blitDeck():
    for i in range(20):
        screen.blit(cardPictures.cardBack, (cardStartX - cardHalfHeight + i, cardStartY - cardHalfWidth - i))

def blitBet():
    msg = "{bet:.2f} $"

    if service.playerHasSplit() == False:
        bet = service.getPlayerTotalBet()
    else:
        bet = (service.getPlayerTotalBet()) / 2
        message_to_screen(msg.format(bet=bet), yellow, fontBet, chipPosX - chipWidth, chipPosY + chipHeight / 2 + 50)

    message_to_screen(msg.format(bet=bet), yellow, fontBet, chipPosX - chipWidth, chipPosY + chipHeight / 2)

def blitStacks():
    stacks = 0
    if service.playerHasSplit() == False and service.playerHasDoubled() == False:
        for i in range(service.getPlayerTotalAmountOfChipsInBet()):
            if i != 0 and i % 10 == 0:
                stacks += 1

            screen.blit(service.getPlayerListOfChips()[i].img, (chipPosX + 75 * stacks, chipPosY - 5 * i + 50 * stacks))

    if service.playerHasSplit() == True or service.playerHasDoubled() == True:
        for i in range(int(service.getPlayerTotalAmountOfChipsInBet() / 2)):
            if i != 0 and i % 10 == 0:
                stacks += 1

            screen.blit(service.getPlayerListOfSplitOrDoubleChips()[i].img,
                        (chipPosX + 75 * stacks, chipPosY - 5 * i + 50 * stacks))
            screen.blit(service.getPlayerListOfSplitOrDoubleChips()[i].img,
                        (chipPosX + 75 * stacks, chipPosY + 50 - 5 * i + 50 * stacks))

def updateBet():
    blitStacks()
    blitBet()

def updateScreen():
    screen.fill(green)

    message_to_screen("Dealer must draw to 16 and stand on all 17's", white, fontChips, screenWidth / 2, screenHeight / 2)

    pygame.draw.ellipse(screen, yellow,
                        (int(chipPosX - chipWidth / 2), int(chipPosY - chipHeight / 2), chipWidth * 2, chipHeight * 2),
                        2)

    updateBtns()
    updateScore()
    blitDeck()
    updateChips()
    updateBet()

    if service.isHandActive() is True:
        markActivePile()
        blitPlayerCards()
        blitDealerCards()

def playerNewCard(a, d, cardX, cardY):
    theCard = service.drawNewCard()

    for i in range(int(turns)):

        if service.playerHasSplit() == False:
            cardX -= ((cardStartX - cardPosX) - cardDisplacemnet * service.getPlayerAmountOfCards()) / turns
            cardY += ((cardPosY - cardStartY) - cardDisplacemnet * service.getPlayerAmountOfCards()) / turns
        elif service.playerHasSplit() == True and service.playerSplitStand() == False:
            cardX -= ((cardStartX - (cardPosX + 180)) - cardDisplacemnet * service.getPlayerSplitAmountOfCards()) / turns
            cardY += ((cardPosY - cardStartY) - cardDisplacemnet * service.getPlayerSplitAmountOfCards()) / turns
        elif service.playerHasSplit() == True and service.playerSplitStand() == True:
            cardX -= ((cardStartX - (cardPosX - 180)) - cardDisplacemnet * service.getPlayerAmountOfCards()) / turns
            cardY += ((cardPosY - cardStartY) - cardDisplacemnet * service.getPlayerAmountOfCards()) / turns

        drawCard(cardX, cardY, theCard.img, adjustAngle(a, d, i))
        pygame.display.update()
        updateScreen()

    if service.playerHasSplit() == True and service.playerSplitStand() == False:
        service.addNewSplitCardToPlayer(theCard)
        if service.getPlayerSplitScore() > 21:
            service.turnPlayerSplitStandOn()
    else:
        service.addNewCardToPlayer(theCard)

    updateScreen()

def dealerNewCard(a, d, cardX, cardY):
    theCard = service.drawNewCard()

    for i in range(int(turns)):
        if service.dealer.getAmountOfCards() == dealerSpacedCardsLimit:
            moveCards(i)

        if service.dealer.getAmountOfCards() < dealerSpacedCardsLimit:
            cardX -= ((cardStartX - cardPosX + (cardWidth + cardDisplacemnet)) - (
                        cardWidth + cardDisplacemnet) * service.dealer.getAmountOfCards()) / turns
        else:
            cardX -= ((cardStartX - cardPosX + (
                        cardWidth + cardDisplacemnet)) - cardDisplacemnet * service.dealer.getAmountOfCards()) / turns

        drawCard(cardX, cardY, theCard.img, adjustAngle(a, d, i))
        pygame.display.update()
        updateScreen()

    service.dealer.addNewCard(theCard)

    updateScreen()

def dealerSecondCard(cardX):
    for i in range(int(turns)):
        cardX -= (cardStartX - cardPosX) / turns
        screen.blit(cardPictures.cardBack, (int(cardX - cardHalfWidth), int(cardStartY - cardHalfHeight)))
        pygame.display.update()
        updateScreen()

    service.dealer.faceDownCards += 1
    updateScreen()

def turnDealersSecondCard(a, d):
    theCard = service.drawNewCard()

    service.dealer.faceDownCards -= 1
    for i in range(int(turns)):
        drawCard(cardPosX, cardStartY, theCard.img, adjustAngle(a, d, i))
        pygame.display.update()
        updateScreen()

    service.dealer.addNewCard(theCard)

def stand():
    if service.playerHasSplit() is True and service.playerSplitStand() is False:
        service.turnPlayerSplitStandOn()
        updateScreen()
    else:
        turnBtnOff(hitBtn)
        turnBtnOff(standBtn)
        turnBtnOff(doubleBtn)
        turnBtnOff(splitBtn)
        turnDealersSecondCard(a, d)
        updateScreen()

        while service.dealer.getScore() <= 16:
            dealerNewCard(a, d, cardX, cardY)
            updateScreen()

def double():
    service.double()

    playerNewCard(a, d, cardX, cardY)
    updateScreen()

    stand()
    updateScreen()

def split():
    service.player.beforeSplit()
    service.player.afterSplit()

    global cardsMoving
    cardsMoving = True

    for i in range(int(turns)):
        for j in range(service.getPlayerTotalAmountOfCards()):
            cardX = (cardPosX + cardDisplacemnet * j)
            cardY = (cardPosY - cardDisplacemnet * j)

            changeX = (cardPosX - (int(cardX) - 180)) / turns
            changeY = (cardPosY - (int(cardY))) / turns

            if j == 0:
                cardX -= changeX * i
                screen.blit(service.getPlayerLastCard().img, (int(cardX - cardHalfWidth), int(cardY - cardHalfHeight)))

            elif j == 1:
                cardX += changeX * i
                cardY += changeY * i
                screen.blit(service.getPlayerSplitLastCard().img, (int(cardX - cardHalfWidth), int(cardY - cardHalfHeight)))

            #screen.blit(service.getPlayerPile()[j].img, (int(cardX - cardHalfWidth), int(cardY - cardHalfHeight)))

        #if i == turns - 1:
        #    service.player.afterSplit()

        if i == turns - 1:

            cardsMoving = False

        pygame.display.update()
        updateScreen()

def clearDealerCards(i):
    if service.dealer.getAmountOfCards() == 1:
        amountOfCards = 2
    else:
        amountOfCards = service.dealer.getAmountOfCards()
    for j in range(amountOfCards):

        cardY = int(cardStartY - cardHalfHeight)

        if service.dealer.getAmountOfCards() <= dealerSpacedCardsLimit:

            cardX = int(cardPosX - (cardWidth + cardDisplacemnet + cardHalfWidth) + (cardWidth + cardDisplacemnet) * j)

        else:

            cardX = int(cardPosX - (cardWidth + cardDisplacemnet + cardHalfWidth) + cardDisplacemnet * j)

        changeX = (cardX - 200) / turns
        changeY = (cardY + cardHeight + 20) / turns

        x = cardX - changeX * i
        y = cardY - changeY * i

        if service.dealer.getAmountOfCards() == 1 and j == 1:
            cardImg = cardPictures.cardBack
        else:
            cardImg = service.dealer.getPile()[j].img

        screen.blit(cardImg, (int(x), int(y)))

def clearPlayerCards(i):
    if service.playerHasSplit() == False:
        for j in range(service.getPlayerAmountOfCards()):

            cardX = int(cardPosX - cardHalfWidth + cardDisplacemnet * j)
            cardY = int(cardPosY - cardHalfHeight - cardDisplacemnet * j)

            changeX = (cardX - 200) / turns
            changeY = (cardY + cardHeight + 20) / turns

            x = cardX - changeX * i
            y = cardY - changeY * i

            screen.blit(service.getPlayerPile()[j].img, (int(x), int(y)))

    else:
        for j in range(service.getPlayerAmountOfCards()):

            cardX = int(cardPosX - cardHalfWidth - 180 + cardDisplacemnet * j)
            cardY = int(cardPosY - cardHalfHeight - cardDisplacemnet * j)

            changeX = (cardX - 200) / turns
            changeY = (cardY + cardHeight + 20) / turns

            x = cardX - changeX * i
            y = cardY - changeY * i

            screen.blit(service.getPlayerPile()[j].img, (int(x), int(y)))

        for k in range(service.getPlayerSplitAmountOfCards()):

            cardX = int(cardPosX - cardHalfWidth + 180 + cardDisplacemnet * k)
            cardY = int(cardPosY - cardHalfHeight - cardDisplacemnet * k)

            changeX = (cardX - 200) / turns
            changeY = (cardY + cardHeight + 20) / turns

            x = cardX - changeX * i
            y = cardY - changeY * i

            screen.blit(service.getPlayerSplitPile()[k].img, (int(x), int(y)))

def clearTable():
    for i in range(int(turns)):
        clearDealerCards(i)
        clearPlayerCards(i)
        pygame.display.update()
        updateScreen()

def askForInsurance():
    turnBtnOn(yesBtn)
    turnBtnOn(noBtn)
    pygame.draw.rect(screen, white, (askForInsuranceWindowX, askForInsuranceWindowY, askForInsuranceWindowWidth, askForInsuranceWindowHeight))
    message_to_screen("Do you want insurance?", black, fontChips, screenWidth / 2, (screenHeight - 100) / 2)
    yesBtn.draw(screen, black)
    noBtn.draw(screen, black)

def dealNewHand():
    service.startHand()
    service.updateLastBet()
    playerNewCard(a, d, cardX, cardY)
    dealerNewCard(a, d, cardX, cardY)
    playerNewCard(a, d, cardX, cardY)
    dealerSecondCard(cardX)
    if service.dealer.getLastCard().value == 11:
        askForInsurance()

def restart():
    clearTable()
    service.resetDealerAndPlayer()
    updateScreen()

def changeBet(button, chip):
    if button == 1:
        service.placeBet(chip)
    elif button == 3:
        service.subtractChip(chip)

    pygame.display.update()
    updateScreen()

def gameEnded():
    blitWinnerMsg()
    pygame.display.update()
    service.executeBetWithDelay()
    restart()

updateScreen()

while running:

    if service.gameEnded() is True:
        gameEnded()

    for event in pygame.event.get():
        pos = pygame.mouse.get_pos()

        if event.type == pygame.QUIT:  # pygame.QUIT funkar inte... Returnerar fel värde...
            running = False

        elif event.type == pygame.MOUSEBUTTONDOWN and dealBtn.isOver(pos) is True and dealBtn.enabled is True:
            dealNewHand()

        elif event.type == pygame.MOUSEBUTTONDOWN and hitBtn.isOver(pos) is True and hitBtn.enabled is True:
            playerNewCard(a, d, cardX, cardY)
            updateScreen()

        elif event.type == pygame.MOUSEBUTTONDOWN and standBtn.isOver(pos) is True and standBtn.enabled is True:
            stand()

        elif event.type == pygame.MOUSEBUTTONDOWN and doubleBtn.isOver(pos) is True and doubleBtn.enabled is True:
            double()

        elif event.type == pygame.MOUSEBUTTONDOWN and splitBtn.isOver(pos) is True and splitBtn.enabled is True:
            split()

        elif event.type == pygame.MOUSEBUTTONDOWN and bet100Btn.isOver(pos) is True and bet100Btn.enabled is True:
            changeBet(event.button, Chips.chip100)
        elif event.type == pygame.MOUSEBUTTONDOWN and bet25Btn.isOver(pos) is True and bet25Btn.enabled is True:
            changeBet(event.button, Chips.chip25)
        elif event.type == pygame.MOUSEBUTTONDOWN and bet10Btn.isOver(pos) is True and bet10Btn.enabled is True:
            changeBet(event.button, Chips.chip10)
        elif event.type == pygame.MOUSEBUTTONDOWN and bet5Btn.isOver(pos) is True and bet5Btn.enabled is True:
            changeBet(event.button, Chips.chip5)
        elif event.type == pygame.MOUSEBUTTONDOWN and bet1Btn.isOver(pos) is True and bet1Btn.enabled is True:
            changeBet(event.button, Chips.chip1)
        elif event.type == pygame.MOUSEBUTTONDOWN and bet0point1Btn.isOver(pos) is True and bet0point1Btn.enabled is True:
            changeBet(event.button, Chips.chip0point1)

        elif event.type == pygame.MOUSEBUTTONDOWN and clearBtn.isOver(pos) is True and clearBtn.enabled is True:
            service.clearBet()
            updateScreen()
        elif event.type == pygame.MOUSEBUTTONDOWN and copyBtn.isOver(pos) is True and copyBtn.enabled is True:
            service.copyLastBet()
            dealNewHand()

        elif event.type == pygame.MOUSEBUTTONDOWN and yesBtn.isOver(pos) is True and yesBtn.enabled:
            service.insurance()
            updateScreen()
        elif event.type == pygame.MOUSEBUTTONDOWN and noBtn.isOver(pos) is True and noBtn.enabled:
            updateScreen()

        break

    pygame.display.update()


from functools import wraps
from itertools import chain

from django.contrib import messages
from django.contrib.admin.utils import unquote
from django.db.models.query import QuerySet
from django.http import Http404, HttpResponseRedirect
from django.http.response import HttpResponseBase
from django.views.generic import View
from django.views.generic.detail import SingleObjectMixin
from django.views.generic.list import MultipleObjectMixin
from django.urls import re_path, reverse

class BaseDjangoObjectActions(object):
    """
    ModelAdmin mixin to add new actions just like adding admin actions.

    Attributes
    ----------
    model : django.db.models.Model
        The Django Model these actions work on. This is populated by Django.
    change_actions : list of str
        Write the names of the methods of the model admin that can be used as
        tools in the change view.
    changelist_actions : list of str
        Write the names of the methods of the model admin that can be used as
        tools in the changelist view.
    tools_view_name : str
        The name of the Django Object Actions admin view, including the 'admin'
        namespace. Populated by `_get_action_urls`.
    """

    change_actions = []
    changelist_actions = []
    tools_view_name = None

    # EXISTING ADMIN METHODS MODIFIED
    #################################

    def get_urls(self):
        """Prepend `get_urls` with our own patterns."""
        urls = super(BaseDjangoObjectActions, self).get_urls()
        return self._get_action_urls() + urls

    def change_view(self, request, object_id, form_url="", extra_context=None):
        extra_context = extra_context or {}
        extra_context.update(
            {
                "objectactions": [
                    self._get_tool_dict(action)
                    for action in self.get_change_actions(request, object_id, form_url)
                ],
                "tools_view_name": self.tools_view_name,
            }
        )
        return super(BaseDjangoObjectActions, self).change_view(
            request, object_id, form_url, extra_context
        )

    def changelist_view(self, request, extra_context=None):
        extra_context = extra_context or {}
        extra_context.update(
            {
                "objectactions": [
                    self._get_tool_dict(action)
                    for action in self.get_changelist_actions(request)
                ],
                "tools_view_name": self.tools_view_name,
            }
        )
        return super(BaseDjangoObjectActions, self).changelist_view(
            request, extra_context
        )

    # USER OVERRIDABLE
    ##################

    def get_change_actions(self, request, object_id, form_url):
        """
        Override this to customize what actions get to the change view.

        This takes the same parameters as `change_view`.

        For example, to restrict actions to superusers, you could do:

            class ChoiceAdmin(DjangoObjectActions, admin.ModelAdmin):
                def get_change_actions(self, request, **kwargs):
                    if request.user.is_superuser:
                        return super(ChoiceAdmin, self).get_change_actions(
                            request, **kwargs
                        )
                    return []
        """
        return self.change_actions

    def get_changelist_actions(self, request):
        """
        Override this to customize what actions get to the changelist view.
        """
        return self.changelist_actions

    # INTERNAL METHODS
    ##################

    def _get_action_urls(self):
        """Get the url patterns that route each action to a view."""
        actions = {}

        model_name = self.model._meta.model_name
        # e.g.: polls_poll
        base_url_name = "%s_%s" % (self.model._meta.app_label, model_name)
        # e.g.: polls_poll_actions
        model_actions_url_name = "%s_actions" % base_url_name

        self.tools_view_name = "admin:" + model_actions_url_name

        # WISHLIST use get_change_actions and get_changelist_actions
        # TODO separate change and changelist actions
        for action in chain(self.change_actions, self.changelist_actions):
            actions[action] = getattr(self, action)
        return [
            # change, supports the same pks the admin does
            # https://github.com/django/django/blob/stable/1.10.x/django/contrib/admin/options.py#L555
            re_path(
                r"^(?P<pk>.+)/actions/(?P<tool>\w+)/$",
                self.admin_site.admin_view(  # checks permissions
                    ChangeActionView.as_view(
                        model=self.model,
                        actions=actions,
                        back="admin:%s_change" % base_url_name,
                        current_app=self.admin_site.name,
                    )
                ),
                name=model_actions_url_name,
            ),
            # changelist
            re_path(
                r"^actions/(?P<tool>\w+)/$",
                self.admin_site.admin_view(  # checks permissions
                    ChangeListActionView.as_view(
                        model=self.model,
                        actions=actions,
                        back="admin:%s_changelist" % base_url_name,
                        current_app=self.admin_site.name,
                    )
                ),
                # Dupe name is fine. https://code.djangoproject.com/ticket/14259
                name=model_actions_url_name,
            ),
        ]

    def _get_tool_dict(self, tool_name):
        """Represents the tool as a dict with extra meta."""
        tool = getattr(self, tool_name)
        standard_attrs, custom_attrs = self._get_button_attrs(tool)
        return dict(
            name=tool_name,
            label=getattr(tool, "label", tool_name.replace("_", " ").capitalize()),
            standard_attrs=standard_attrs,
            custom_attrs=custom_attrs,
        )

    def _get_button_attrs(self, tool):
        """
        Get the HTML attributes associated with a tool.

        There are some standard attributes (class and title) that the template
        will always want. Any number of additional attributes can be specified
        and passed on. This is kinda awkward and due for a refactor for
        readability.
        """
        attrs = getattr(tool, "attrs", {})
        # href is not allowed to be set. should an exception be raised instead?
        if "href" in attrs:
            attrs.pop("href")
        # title is not allowed to be set. should an exception be raised instead?
        # `short_description` should be set instead to parallel django admin
        # actions
        if "title" in attrs:
            attrs.pop("title")
        default_attrs = {
            "class": attrs.get("class", ""),
            "title": getattr(tool, "short_description", ""),
        }
        standard_attrs = {}
        custom_attrs = {}
        for k, v in dict(default_attrs, **attrs).items():
            if k in default_attrs:
                standard_attrs[k] = v
            else:
                custom_attrs[k] = v
        return standard_attrs, custom_attrs

class DjangoObjectActions(BaseDjangoObjectActions):
    change_form_template = "django_object_actions/change_form.html"
    change_list_template = "django_object_actions/change_list.html"

class BaseActionView(View):
    """
    The view that runs a change/changelist action callable.

    Attributes
    ----------
    back : str
        The urlpattern name to send users back to. This is set in
        `_get_action_urls` and turned into a url with the `back_url` property.
    model : django.db.model.Model
        The model this tool operates on.
    actions : dict
        A mapping of action names to callables.
    """

    back = None
    model = None
    actions = None
    current_app = None

    @property
    def view_args(self):
        """
        tuple: The argument(s) to send to the action (excluding `request`).

        Change actions are called with `(request, obj)` while changelist
        actions are called with `(request, queryset)`.
        """
        raise NotImplementedError

    @property
    def back_url(self):
        """
        str: The url path the action should send the user back to.

        If an action does not return a http response, we automagically send
        users back to either the change or the changelist page.
        """
        raise NotImplementedError

    def get(self, request, tool, **kwargs):
        # Fix for case if there are special symbols in object pk
        for k, v in self.kwargs.items():
            self.kwargs[k] = unquote(v)

        try:
            view = self.actions[tool]
        except KeyError:
            raise Http404("Action does not exist")

        ret = view(request, *self.view_args)
        if isinstance(ret, HttpResponseBase):
            return ret

        return HttpResponseRedirect(self.back_url)

    # HACK to allow POST requests too
    post = get

    def message_user(self, request, message):
        """
        Mimic Django admin actions's `message_user`.

        Like the second example:
        https://docs.djangoproject.com/en/1.9/ref/contrib/admin/actions/#custom-admin-action
        """
        messages.info(request, message)

class ChangeActionView(SingleObjectMixin, BaseActionView):
    @property
    def view_args(self):
        return (self.get_object(),)

    @property
    def back_url(self):
        return reverse(
            self.back, args=(self.kwargs["pk"],), current_app=self.current_app
        )

class ChangeListActionView(MultipleObjectMixin, BaseActionView):
    @property
    def view_args(self):
        return (self.get_queryset(),)

    @property
    def back_url(self):
        return reverse(self.back, current_app=self.current_app)

def takes_instance_or_queryset(func):
    """Decorator that makes standard Django admin actions compatible."""

    @wraps(func)
    def decorated_function(self, request, queryset):
        # func follows the prototype documented at:
        # https://docs.djangoproject.com/en/dev/ref/contrib/admin/actions/#writing-action-functions
        if not isinstance(queryset, QuerySet):
            try:
                # Django >=1.8
                queryset = self.get_queryset(request).filter(pk=queryset.pk)
            except AttributeError:
                try:
                    # Django >=1.6,<1.8
                    model = queryset._meta.model
                except AttributeError:  # pragma: no cover
                    # Django <1.6
                    model = queryset._meta.concrete_model
                queryset = model.objects.filter(pk=queryset.pk)
        return func(self, request, queryset)

    return decorated_function

def action(
    function=None, *, permissions=None, description=None, label=None, attrs=None
):
    """
    Conveniently add attributes to an action function:

        @action(
            permissions=['publish'],
            description='Mark selected stories as published',
            label='Publish'
        )
        def make_published(self, request, queryset):
            queryset.update(status='p')

    This is equivalent to setting some attributes (with the original, longer
    names) on the function directly:

        def make_published(self, request, queryset):
            queryset.update(status='p')
        make_published.allowed_permissions = ['publish']
        make_published.short_description = 'Mark selected stories as published'
        make_published.label = 'Publish'

    This is the django-object-actions equivalent of
    https://docs.djangoproject.com/en/stable/ref/contrib/admin/actions/#django.contrib.admin.action
    """

    def decorator(func):
        if permissions is not None:
            func.allowed_permissions = permissions
        if description is not None:
            func.short_description = description
        if label is not None:
            func.label = label
        if attrs is not None:
            func.attrs = attrs
        return func

    if function is None:
        return decorator
    else:
        return decorator(function)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import pandas
import functools

from pathlib import Path

from utils.imports import import_textgrid, import_srt
from utils.corpus import import_csv_textcorpus, join_corpus_files
from utils.kfold import create_kfolds

from argparse import ArgumentParser, RawTextHelpFormatter

DESCRIPTION = """
Paratoi adnoddau ychwanegol ar gyfer hyfforddi rhagor.

© Prifysgol Bangor University

"""
def create_kfolds_and_lm_data(bangor_data_root_dir, csv_file_path, target_kfolds_dir):
    create_kfolds(csv_file_path, target_kfolds_dir, 10)

    target_languagemodel_data_root_dir = os.path.join(target_kfolds_dir, "lm-data")
    Path(target_languagemodel_data_root_dir).mkdir(parents=True, exist_ok=True)

    base_text_corpus_file_path = os.path.join(bangor_data_root_dir, "lm-data", "corpus.clean.txt")
    for kfold_csv in os.listdir(target_kfolds_dir):
        if kfold_csv.startswith("train_"):
            corpus_files = []
            corpus_files.append(import_csv_textcorpus(os.path.join(target_kfolds_dir, kfold_csv), target_languagemodel_data_root_dir))
            corpus_files.append(base_text_corpus_file_path)
            corpus_file_path = join_corpus_files(corpus_files, target_languagemodel_data_root_dir, "corpus.%s.union.clean.txt" % kfold_csv.replace(".csv",""))
            print ("lm-data for kfold %s created in %s" % (kfold_csv, corpus_file_path))

def main(bangor_data_root_dir, finetune_data_file, target_finetuning_root_dir, **args):

    target_languagemodel_data_root_dir = os.path.join(target_finetuning_root_dir, "lm-data")
    Path(target_languagemodel_data_root_dir).mkdir(parents=True, exist_ok=True)

    target_csv_file_path = os.path.join(target_finetuning_root_dir, "deepspeech.csv")

    #
    transcribed_clips = []
    with open(finetune_data_file, 'r', encoding='utf-8') as finetune_files:
        for finetune_file_path in finetune_files:
            if finetune_file_path.startswith("#"):
                continue

            finetune_file_path = finetune_file_path.rstrip()
            if not os.path.isfile(finetune_file_path):
                continue

            if finetune_file_path.endswith(".TextGrid"):
                transcribed_clips.append(import_textgrid(target_csv_file_path, finetune_file_path))
            elif finetune_file_path.endswith(".srt"):
                transcribed_clips.append(import_srt(target_csv_file_path, finetune_file_path))

    df_transcribed_clips = pandas.concat(transcribed_clips)
    df_transcribed_clips.to_csv(target_csv_file_path, index=False)

    # collect transcriptions into additions for fine tune training a language model
    base_text_corpus_file_path = os.path.join(bangor_data_root_dir, "lm-data", "corpus.clean.txt")
    corpus_files = []
    corpus_files.append(import_csv_textcorpus(target_csv_file_path, target_languagemodel_data_root_dir))
    corpus_files.append(base_text_corpus_file_path)
    corpus_file_path = join_corpus_files(corpus_files, target_languagemodel_data_root_dir, "corpus.union.clean.txt")

    # create k-folds for determining new WER from fine tuned data.
    create_kfolds_and_lm_data(bangor_data_root_dir, target_csv_file_path, os.path.join(target_finetuning_root_dir, "kfolds"))

    #
    print ("Import fine tuning data to %s finished." % (target_finetuning_root_dir))
    print ("Corpus for fine tuning language model is at %s" % corpus_file_path)

if __name__ == "__main__":

    parser = ArgumentParser(description=DESCRIPTION, formatter_class=RawTextHelpFormatter)

    parser.add_argument("--bangor_dir", dest="bangor_data_root_dir", default="/data/bangor")
    parser.add_argument("--target_dir", dest="target_finetuning_root_dir", help="target folder for all finetuning resources. should have an accompanying wav file (of the same name but with .wav extension)", default="/data/finetuning")
    parser.add_argument("--finetuning_data_file", dest="finetune_data_file", help="File containing paths (one per line) to srt and/or TextGrid files", required=True)
    # parser.add_argument("-c", dest="base_text_corpus_file_path", help=" file path to a text corpus that will be fined tuned e.g. OSCAR corpus", required=True)

    parser.set_defaults(func=main)
    args = parser.parse_args()
    args.func(**vars(args))


# coding=utf-8
import os
import os.path as osp
from collections import defaultdict
from copy import deepcopy

from tqdm import tqdm
import sys
import matplotlib.pyplot as plt

from misc.pascal_voc_utils import Reader, PaddingModify, Writer
from misc.utils import load_pkl, save_pkl

def box_scales(path, target_path):
    '''
    获得所有bbox的大小尺度
    :param path:
    :return:
    '''
    scale_counters = defaultdict(set)
    min_height, min_width, max_height, max_width = sys.maxsize, sys.maxsize, 0, 0
    minH_bbox, minW_bbox, maxH_bbox, maxW_bbox = None, None, None, None
    for root, _, filenames in os.walk(path):
        for filename in tqdm(filenames, desc=root):
            if filename.endswith('xml'):
                op = osp.join(root, filename)
                obj = Reader(op).get_objects()

                for c, box in zip(obj['category_name'], obj['bboxes']):
                    x_min, y_min, x_max, y_max = box
                    height, width = y_max - y_min, x_max - x_min
                    scale_counters[c].add((height, width))

                    if height < min_height:
                        min_height = height
                        minH_bbox = (height, width)

                    if width < min_width:
                        min_width = width
                        minW_bbox = (height, width)

                    if height > max_height:
                        max_height = height
                        maxH_bbox = (height, width)

                    if width > max_width:
                        max_width = width
                        maxW_bbox = (height, width)

    print('minH_bbox, minW_bbox, maxH_bbox, maxW_bbox')
    print(minH_bbox, minW_bbox, maxH_bbox, maxW_bbox)
    save_pkl(target_path, scale_counters)

def scatter_image(pkl_path):
    '''
    read pkl file and show the box scales
    :param pkl_path:
    :return:
    '''
    data = load_pkl(pkl_path)
    fig, axs = plt.subplots(len(data.keys())+1)
    for index, c in enumerate(data.keys()):
        for (h, w) in tqdm(data[c], desc=c):
            axs[index].scatter(h, w, c = 'r', alpha = 0.8, s = 2)
        axs[index].set_xlim(0, 250)
        axs[index].set_ylim(0, 250)
    plt.title(pkl_path)
    plt.show()

def bbox_img_counter(path, count_img = False):
    counter, img_counter = defaultdict(int), 0
    for root, _, filenames in os.walk(path):
        for filename in filenames:
            if filename.endswith('xml'):
                objs = Reader(osp.join(root, filename)).get_objects()
                for label in objs['category_name']:
                    counter[label] += 1
                if count_img:
                    if osp.exists(osp.join(root, filename).replace('xml', 'jpg')):
                        img_counter += 1

    print(counter, img_counter)

def enlarge_xml(path, target_path, padding_pixel):
    '''
    >>> enlarge_xml('/Users/sober/Downloads/800/test/large_xml',
    >>>             '/Users/sober/Downloads/make_data/enlarge_xml',
    >>>             padding_pixel=15)
    :param path:
    :param target_path:
    :param padding_pixel:
    :return:
    '''
    os.makedirs(target_path, exist_ok=True)
    for root, _, filenames in os.walk(path):
        # sub_path = root.replace(path, '').strip('/')
        for filename in tqdm(sorted(filenames)):
            if filename.endswith(".xml"):
                op = os.path.join(root, filename)
                # tp_root = os.path.join(target_path, sub_path)
                # os.makedirs(tp_root, exist_ok=True)

                # tp = os.path.join(tp_root, filename.replace('vis', 'rgb'))

                PaddingModify(op, op.replace(root, target_path), padding_pixel).run()

def drop_small(path, target_path, min_size = 0.01):
    os.makedirs(target_path, exist_ok=True)
    for root, _, filenames in os.walk(path):
        for filename in filenames:
            if filename.endswith('xml'):
                objs = Reader(osp.join(root, filename)).get_objects()
                width, height = objs['width'], objs['height']
                obj_dicts = deepcopy(objs)
                obj_dicts['name'], obj_dicts['bboxes'], obj_dicts['category_name'], obj_dicts[
                    'difficult'] = [], [], [], []
                for name, category_name, bbox, difficult in zip(objs['name'], objs['category_name'], objs['bboxes'],
                                                                objs['difficult']):
                    xmin, ymin, xmax, ymax = bbox
                    if xmax - xmin <= width * min_size or ymax - ymin <= height *min_size:
                        print('Drop: ', filename, (xmin, ymin, xmax, ymax))
                    else:
                        obj_dicts['name'].append(name)
                        obj_dicts['category_name'].append(name)
                        obj_dicts['bboxes'].append(bbox)
                        obj_dicts['difficult'].append(difficult)

                if len(obj_dicts['bboxes']) > 0:
                    writer = Writer(obj_dicts['path'], obj_dicts['width'], obj_dicts['height'], database =
                    osp.split(obj_dicts['path'])[0])
                    writer.addBboxes(obj_dicts['bboxes'], obj_dicts['category_name'])
                    writer.save(osp.join(root, filename).replace(path, target_path))

def check_bbox(path, min_size = 0.01):
    for root, _, filenames in os.walk(path):
        for filename in filenames:
            if filename.endswith('xml'):
                objs = Reader(osp.join(root, filename)).get_objects()
                width, height = objs['width'], objs['height']
                for (xmin, ymin, xmax, ymax) in objs['bboxes']:
                     if xmax - xmin <= width * min_size or ymax - ymin <= height *min_size:
                         print(filename, (xmin, ymin, xmax, ymax))

def a(path):
    counter = 0
    for root, _, filenames in os.walk(path):
        for filename in filenames:
            if filename.endswith('jpg'):
                if int(filename.split('.')[0].split('_')[-1]) == 0:
                    counter += 1
    print(counter)

if __name__ == '__main__':
    # drop_small('/Users/sober/Downloads/Project/2022_pwd/disease_split/disease',
    #            '/Users/sober/Downloads/Project/2022_pwd/disease_split/disease_drop_small')

    # enlarge_xml('/Users/sober/Downloads/Project/2022_pwd/disease_split/disease_drop_small',
    #             '/Users/sober/Downloads/Project/2022_pwd/disease_split/disease_enlarge8', padding_pixel= 8)

    # check_bbox('/Users/sober/Downloads/Project/2022_pwd/disease_split/disease')

    # box_scales(r'E:\make_pine_data\rgb\auged_data\val\xml', r'H:\val_aug_scales.pkl')
    # scatter_image(r"H:\val_aug_scales.pkl")

    # bbox_img_counter('/Users/sober/Downloads/Project/2022_pwd/disease_split/yolo/val', True)
    # a('/Users/sober/Downloads/Project/2022_pwd/disease_split/yolo/val_with_normal')

    import cv2
    import numpy as np
    img = cv2.imread('/Users/sober/Downloads/Project/2022_pwd/temp/kangsan/test/img/AP_IMAGE_512/FR_GS_AP_35712028_443.tif', cv2.IMREAD_UNCHANGED)
    print(img.img_shape, np.unique(img))
    # p = '/Users/sober/Downloads/Project/2022_pwd/temp/zezhu/test/label/PI_512/METADATA/FR_JJ_PI_6049_FGT_META.json'
    # # encoding = 'cp1250', errors = 'ignore'
    # from bs4 import UnicodeDammit
    # with open(p, encoding='utf-8-sig' ) as f:
    #     context = f.read()
    #     print(context)
    #     print(context[1:])

        # suggestion = UnicodeDammit(context)
        # print(suggestion.original_encoding)


# python3 partitions.py -i test.txt -t nt -o nexus

import argparse

parser = argparse.ArgumentParser(description="Create partition files from catfasta output")
parser.add_argument("-i", "--input", type=str, help="Catfasta partition file")
parser.add_argument('-t', '--sequence_type', choices=['aa', 'nt'], help="Is input file from amino acid or nucleotide "
                                                                        "supermatrix?")
parser.add_argument('-o', '--output', choices=['raxml', 'nexus'], help="Choose output file type")

args = parser.parse_args()

file = open(args.input)
lines = file.readlines()
rrna = ['12S', '16S', '18S', '28S']

# AA gene partitions

if args.sequence_type == 'aa':
    outputaa = open(f'partitions_aa.txt', 'w')
    if args.output == 'nexus':
        outputaa.write('#nexus\n'
                       'begin sets;\n')
    for line in lines:
        line = line.strip()
        split = line.split('=')         # split[0] eg all_aa/12S.fasta, split[1] eg 1-436
        start = split[0].split('/')     # start[0] eg all_aa, start[1] eg 12s.fasta
        if any(r in start[1] for r in rrna):    # Check for rRNA genes
            start[0] = 'DNA'
        else:
            start[0] = 'mtART'
        if args.output == 'raxml':
            outputaa.write(f'{start[0]}, {start[1]}={split[1]}\n')
        if args.output == 'nexus':
            outputaa.write(f'  charset {start[1]}={split[1]};\n')

    if args.output == 'nexus':
        outputaa.write('end;')

# NT Gene Partitions

if args.sequence_type == 'nt':
    outputnt = open(f'partitions_gene.txt', 'w')
    if args.output == 'nexus':
        outputnt.write('#nexus\n'
                       'begin sets;\n')
    for line in lines:
        line = line.strip()
        split = line.split('=')
        start = split[0].split('/')
        start[0] = 'DNA'
        if args.output == 'raxml':
            outputnt.write(f'{start[0]}, {start[1]}={split[1]}\n')
        if args.output == 'nexus':
            outputnt.write(f'  charset {start[1]}={split[1]};\n')

    # NT Codon Partitions

    output123 = open(f'partitions_codon123.txt', 'w')
    #output12 = open(f'partitions_codon12.txt', 'w')
    if args.output == 'nexus':
        output123.write('#nexus\n'
                       'begin sets;\n')
        #output12.write('#nexus\n'
                       #'begin sets;\n')
    for line in lines:
        line = line.strip()
        split = line.split('=')
        start = split[0].split('/')
        start[0] = 'DNA'
        if any(r in start[1] for r in rrna):
            if args.output == 'raxml':
                output123.write(f'{start[0]}, {start[1]}={split[1]}\n')
                #output12.write(f'{start[0]}, {start[1]}={split[1]}\n')
            if args.output == 'nexus':
                output123.write(f'  charset {start[1]}={split[1]};\n')
                #output12.write(f'  charset {start[1]}={split[1]};\n')

        else:
            part = start[1].split('.')
            pos = split[1].split('-')
            if args.output == 'raxml':
                output123.write(f'{start[0]}, {part[0]}.1 ={pos[0]}-{pos[1]}\\3\n')
                output123.write(f'{start[0]}, {part[0]}.2 = {int(pos[0])+1}-{pos[1]}\\3\n')
                output123.write(f'{start[0]}, {part[0]}.3 = {int(pos[0])+2}-{pos[1]}\\3\n')
                #output12.write(f'{start[0]}, {part[0]}.1 ={pos[0]}-{pos[1]}\\3\n')
                #output12.write(f'{start[0]}, {part[0]}.2 = {int(pos[0])+1}-{pos[1]}\\3\n')
            if args.output == 'nexus':
                output123.write(f'  charset {part[0]}.1 ={split[1]}\\3;\n')
                output123.write(f'  charset {part[0]}.2 = {int(pos[0])+1}-{pos[1]}\\3;\n')
                output123.write(f'  charset {part[0]}.3 = {int(pos[0])+2}-{pos[1]}\\3;\n')
                #output12.write(f'  charset {part[0]}.1 ={split[1]};\n')
                #output12.write(f'  charset {part[0]}.2 ={split[1]};\n')
    if args.output == 'nexus':
        outputnt.write('end;')
        #output12.write('end;')
        output123.write('end;')


import random
import numpy as np
import matplotlib.pyplot as plt
import tkinter as tk

def function1(x):
    return x ** 2 - 12 * x + 30

def function2(x):
    return np.sin(x) - np.cos(x)

def function3(x):
    return 2 * (x ** 3) - 3 * x + 15

def square_func(x):
    return x * x

def generate_function_values(n, x_1, x_n, function):
    x = sorted([random.uniform(x_1, x_n) for _ in range(n-1)])
    x.insert(0, x_1)
    x.append(x_n)

    y = list(map(lambda k: function(k), x))

    return (x, y)

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

def get_aitken_dif_div(x, f_x):
    y_current = [0 for _ in range(len(x))]
    y_previous = [0 for _ in range(len(x))]
    y_final = [0 for _ in range(len(x))]

    y_current[0] = f_x[0]
    y_final[0] = f_x[0]

    for i in range(1, len(x)):
        y_current[1] = (f_x[i] - f_x[i-1]) / (x[i] - x[i-1])

        for j in range(2, i+1):
            y_current[j] = (y_current[j-1] - y_previous[j-1]) / (x[i] - x[i-j])

        y_final[i] = y_current[i]
        y_previous = y_current.copy()

    return y_final

def calculate_newton_lagrange_solution(function, x, y, x_val):
    n = len(x)
    L = y[0]
    aikten = get_aitken_dif_div(x, y)
    for i in range(1, n):
        prod = 1
        for k in range(i):
            prod *= (x_val - x[k])
        L += aikten[i] * prod

    real_val = function(x_val)
    delta = abs(real_val - L)
    return L, real_val, delta

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

def get_polynom_coefs(x, y, m):
    n = len(x)
    B = [[0 for _ in range(m)] for _ in range(m)]

    f = [0 for _ in range(m)]
    for i in range(m):
        sum = 0
        for k in range(n):
            sum += y[k] * (x[k] ** i)
        f[i] = sum

    for i in range(m):
        for j in range(m):
            sum = 0
            for k in range(n):
                sum += x[k] ** (i + j)
            B[i][j] = sum

    a = np.linalg.solve(B, f)
    return a

def get_polynom_val(a, m, x):
    d = a[m-1]
    for i in range(1, m):
        d = a[m-i-1] + d * x
    return d

def calculate_horner_sol(function, x, y, m, x_val):
    a = get_polynom_coefs(x, y, m)
    aprox_val = get_polynom_val(a, m, x_val)
    real_val = function(x_val)

    delta = abs(real_val - aprox_val)

    sum = 0
    for i in range(n):
        sum += abs(get_polynom_val(a, m, x[i]) - y[i])

    return aprox_val, real_val, delta, sum

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

def bonus_newton_lagrange_solution(x, y, x_val):
    n = len(x)
    L = y[0]
    aikten = get_aitken_dif_div(x, y)
    for i in range(1, n):
        prod = 1
        for k in range(i):
            prod *= (x_val - x[k])
        L += aikten[i] * prod

    return L

def bonus_horner_sol(x, y, m, x_val):
    a = get_polynom_coefs(x, y, m)
    aprox_val = get_polynom_val(a, m, x_val)

    return aprox_val

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

def draw_graphs(function, x_1, x_n, x, y, m):
    xx = np.linspace(x_1, x_n, 50)

    y1 = function(xx)
    y2 = bonus_newton_lagrange_solution(x, y, xx)
    y3 = bonus_horner_sol(x, y, m, xx)

    fig, axs = plt.subplots(1, 3, figsize=(14, 4))

    axs[0].plot(xx, y1)
    axs[1].plot(xx, y2)
    axs[2].plot(xx, y3)

    axs[0].set_title('Original Function')
    axs[0].set_xlabel('x')
    axs[0].set_ylabel('y')
    axs[1].set_title('Newton Lagrange Estimation')
    axs[1].set_xlabel('x')
    axs[1].set_ylabel('y')
    axs[2].set_title('Square Horner Estimation')
    axs[2].set_xlabel('x')
    axs[2].set_ylabel('y')

    plt.show()

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

n = 3
m = 5
x_1 = 0
x_n = 5

def solve_bonus():
    global n_entry
    global m_entry
    global x_1_entry
    global x_n_entry
    global x_val_entry
    global function_entry
    global response_text
    global content

    response_text.destroy()

    n = int(n_entry.get())
    m = int(m_entry.get())
    x_1 = float(x_1_entry.get())
    x_n = float(x_n_entry.get())
    x_val = float(x_val_entry.get())
    func_name = function_entry.get()

    if func_name == "func1":
        function = function1
    elif func_name == "func2":
        function = function2
    elif func_name == "func3":
        function = function3
    else:
        function = square_func

    x, y = generate_function_values(n, x_1, x_n, function)
    L, real1,  deltaL = calculate_newton_lagrange_solution(
        function, x, y, x_val)

    P, real2,  deltaP, sumP = calculate_horner_sol(function, x, y, m, x_val)

    response = f"L_n = {L} with delta = |L_n(x_val) - f(x_val)| = {deltaL}.\n"
    response += f"P_m = {P} with delta = |P_m(x_val) - f(x_val)| = {deltaP}.\n"
    response += f"|P_m(x_i) - y_i|, pentru i=(0..n), este: {sumP}"

    response_text = tk.Label(content,
                             padx=30,
                             text=response)
    response_text.grid(row=13)
    draw_graphs(function, x_1, x_n, x, y, m)

def bullet_homework():
    global content
    content.destroy()

    global n_entry
    global m_entry
    global x_1_entry
    global x_n_entry
    global x_val_entry
    global function_entry
    global response_text

    content = tk.Frame()
    content.pack(side='top')
    tk.Label(content,
             padx=30,
             text='n: ').grid(row=0)
    n_entry = tk.Entry(content,
                       width=50)
    n_entry.grid(row=1, padx=30)

    tk.Label(content,
             padx=30,
             text='m: ').grid(row=2)
    m_entry = tk.Entry(content,
                       width=50)
    m_entry.grid(row=3, padx=30)

    tk.Label(content,
             padx=30,
             text='x_1: ').grid(row=4)
    x_1_entry = tk.Entry(content,
                         width=50)
    x_1_entry.grid(row=5, padx=30)

    tk.Label(content,
             padx=30,
             text='x_n: ').grid(row=6)
    x_n_entry = tk.Entry(content,
                         width=50)
    x_n_entry.grid(row=7, padx=30)

    tk.Label(content,
             padx=30,
             text='x_val: ').grid(row=8)
    x_val_entry = tk.Entry(content,
                           width=50)
    x_val_entry.grid(row=9, padx=30)

    tk.Label(content,
             padx=30,
             text='function name: ').grid(row=10)
    function_entry = tk.Entry(content,
                              width=50)
    function_entry.grid(row=11, padx=30)

    tk.Button(content,
              text='SOLVE',
              padx=30,
              width=34,
              command=solve_bonus).grid(row=12)

    response_text = tk.Label(content,
                             padx=30,
                             text='')
    response_text.grid(row=13)

def gui():
    window = tk.Tk()
    global content
    window.geometry("800x600")
    window.configure(bg="cornsilk1")
    window.tk_setPalette(background='cornsilk1', foreground='black')

    buttons = tk.Frame()
    buttons.pack(side='top')
    button1 = tk.Button(buttons,
                        text='Homework',
                        width=20,
                        height=5,
                        command=bullet_homework)
    button1.grid(row=0, column=0)

    content = tk.Frame()

    window.mainloop()

gui()


from datetime import date, datetime
import os
from pydub import AudioSegment
from pydub.playback import play
from bs4 import BeautifulSoup
import requests
import pandas as pd
import tkinter as tk
from PIL import Image, ImageTk
from time import sleep

# user-defined parameters
DIRECTORY = '/Users/hao/Documents/dict'
directory = DIRECTORY   # to delete

def check_path(n):
    if not os.path.exists(DIRECTORY + n):
        os.mkdir(DIRECTORY + n)

check_path('/sound')
check_path('/pic')
check_path('/backup')

sound_icon_ = Image.open("/Users/hao/Documents/dict/icon/sound.png")
sound_icon_.thumbnail((20, 20), Image.ANTIALIAS)

# word database
wdb = pd.DataFrame(columns=['word', 'definition', 'comment', 'picture',
                            'pronunciation', 'status', 'updated_date', 'type'])

wdb = wdb.append({'word': 'one',
                  'definition': 'one_definition',
                  'comment': 'one_comment',
                  'picture': 'one_picture',
                  'pronunciation': 'one_pronunciation',
                  'status': 'one_status',
                  'updated_date': 'one_created_date',
                  'type': 'one_type'}, ignore_index=True)
wdb = wdb.append({'word': 'two',
                  'definition': 'two_definition',
                  'comment': 'two_comment',
                  'picture': 'two_picture',
                  'pronunciation': 'two_pronunciation',
                  'status': 'two_status',
                  'updated_date': 'two_created_date',
                  'type': 'two_type'}, ignore_index=True)
wdb = wdb.append({'word': 'three',
                  'definition': 'three_definition',
                  'comment': 'three_comment',
                  'picture': 'three_picture',
                  'pronunciation': 'three_pronunciation',
                  'status': 'three_status',
                  'updated_date': 'three_created_date',
                  'type': 'three_type'}, ignore_index=True)

def pron(s):
    web = 'https://www.dictionary.com/browse/' + s
    page = requests.get(web)
    soup = BeautifulSoup(page.content, 'html.parser')

    # for the mp3 file
    soup2 = soup.find(class_="audio-wrapper css-48y3p0 e1rg2mtf7")
    if not soup2:
        return False
    url = list(list(soup2.children)[1].children)[1].attrs['src']
    r = requests.get(url)
    with open(DIRECTORY + '/sound/' + s + '.mp3', 'wb') as fn:
        fn.write(r.content)

    # for the phonetic symbol
    soup3 = soup.find(class_="pron-spell-content css-z3mf2 evh0tcl2")
    text = []
    for a in list(soup3.children):
        if isinstance(a, str):
            a = str(a)
            if '\u2009n' in a:
                a = a.replace('\u2009', ' ')
            text.append(a)
        else:
            if a.attrs['class'][0] == 'bold':
                text.append('' + a.text + '')
            elif a.attrs['class'][0] == 'italic':
                text.append('' + a.text + '')
    return ''.join(text)

# tkinter setting:
def Text_new(root, w=10, h=3, hb="black", ht=1):
    return tk.Text(master=root, width=w, height=h,
                   highlightbackground=hb, highlightthickness=ht)

def Text_get(t):
    return t.get('1.0', tk.END).strip()

def Text_update(t, m, w):
    t.delete('1.0', tk.END)
    t.insert(tk.END, m)
    w.update()

def Entry_update(e, m):
    e.delete(0, tk.END)
    e.insert(0, m)

# [ he-loh, huh-, hel-oh ]
orignal = "[ he-loh, huh-, hel-oh ]"
bold = []
italics = []

for index, char in enumerate(orignal):
    if char == "<":
        if orignal[index+1] == 'b':
            bold.append(index)
        elif orignal[index+1:index+3] == '/b':
            bold.append(index)
        elif orignal[index+1] == 'i':
            italics.append(index)
        elif orignal[index+1:index+3] == '/i':
            italics.append(index)

orignal[bold[0]:bold[0]+3]
orignal[bold[1]:bold[1]+4]

bold

def Text_format(t):
    orignal = Text_get(t)
    bold = []
    for _ in range(orignal.count('')):
        bold.append()

# def run(option):
#     cur_time = datetime.now().strftime("%m_%d_%H_%M_%S")
#     os.mkdir(e5.get() + '/NewWord_' + cur_time)
#     os.chdir(e5.get() + '/NewWord_' + cur_time)
#
#     txt_file_name = e1.get()
#
#     with open(txt_file_name, 'r') as t:
#         txt = t.readlines()
#
#     word_list = [t[:-1] for t in txt if t[-1] == '\n']
#
#     concat_mp3 = AudioSegment.empty()
#     wrong_list = []
#
#     for i, word in enumerate(word_list, start=1):
#         web = 'https://www.dictionary.com/browse/' + word
#         page = requests.get(web)
#         soup = BeautifulSoup(page.content, 'html.parser')
#         soup2 = soup.find(class_="audio-wrapper css-48y3p0 e1rg2mtf7")
#         if not soup2:
#             wrong_list.append(word)
#             continue
#         url = list(list(soup2.children)[1].children)[1].attrs['src']
#         file_name = str(i) + '_' + word + '.mp3'
#
#         r = requests.get(url)
#         with open(file_name, 'wb') as fn:
#             fn.write(r.content)
#
#         mp3 = AudioSegment.from_mp3(file_name)
#
#         if option == 'mul':
#             silence = int(e2.get()) * mp3.duration_seconds
#         elif option == 'sec':
#             silence = int(e3.get())
#
#         concat_mp3 += mp3
#         concat_mp3 += AudioSegment.silent(duration=1000 * silence)
#
#     concat_mp3.export("_concat.mp3", format="mp3")

# r = Tk()
# r.title('dictionary')
#
# l1 = Label(r, text="From")
# l1.grid(row=0, sticky='E')
# e1 = Entry(r, width=50)
# e1.grid(row=0, column=1, columnspan=10)
# Button(r, text='Select', command=getFileName).grid(row=0, column=11)
#
# l5 = Label(r, text="Save to")
# l5.grid(row=1, sticky='E')
# e5 = Entry(r, width=50)
# e5.insert(0, '/Users/hao/Desktop')
# e5.grid(row=1, column=1, columnspan=10)
# Button(r, text='Select', command=getFileName2).grid(row=1, column=11)
#
# l2 = Label(r, text="By multiple of the word length: ")
# l2.grid(row=2, column=0, sticky='E', columnspan=10)
# e2 = Entry(r, width=2)
# e2.insert(0, 2)
# e2.grid(row=2, column=10)
# Button(r, text='Run', command=lambda: run("mul")).grid(row=2, column=11)
#
# l3 = Label(r, text="By waiting for how many seconds: ")
# l3.grid(row=3, column=0, sticky='E', columnspan=10)
# e3 = Entry(r, width=2)
# e3.insert(0, 1)
# e3.grid(row=3, column=10)
# Button(r, text='Run', command=lambda: run("sec")).grid(row=3, column=11)
#
# e4 = Text(r, height=3)
# e4.grid(row=4, columnspan=12)
# r.mainloop()

# general functions for GUI

# m is the message
# w is the text window
# ww is the window

# main window functions
def update_directory():
    global directory
    directory = e0.get()
    os.chdir(directory)
    Text_update(msg, f'Working directory is updated to {directory}', w1)
    os.system('say "Working directory is updated"')

def load_db():
    if not os.path.isfile(directory + '/db.csv'):
        f = open('db.csv', mode='x')
        f.close()
    global wdb
    wdb = pd.read_csv(directory + '/db.csv')
    Text_update(msg, 'database is loaded!', w1)
    os.system('say "database is loaded"')

def save_db():
    wdb.to_csv(directory + '/db.csv', index=False)

def backup_db():
    wdb.to_csv(directory + '/backup/' +
               str(datetime.now()) + '.csv', index=False)

# to delete
directory = DIRECTORY

# main window GUI

w1 = tk.Tk()
w1.title('dictApp')
w1.geometry('{}x{}'.format(460, 350))

f1 = tk.Frame(w1, bg='cyan', width=450, height=50)
f1.grid(row=0, column=0)
f2 = tk.Frame(w1, bg='blue', width=450, height=300)
f2.grid(row=1, column=0)

l0 = tk.Label(f1, text='directory: ')
l0.grid(row=0, column=0)
e0 = tk.Entry(f1)
e0.grid(row=0, column=1)
e0.insert(0, DIRECTORY)
directory = e0.get()
os.chdir(directory)

b0 = tk.Button(f1, text='Update', command=update_directory)
b0.grid(row=0, column=2)

b1 = tk.Button(f2, text='Load',  command=load_db)
b1.grid(row=1, column=0)

ba = tk.Button(f2, text='Add', command=add)
ba.grid(row=2, column=0)
ea = tk.Entry(f2)
ea.grid(row=2, column=1)
ea.insert(0, 10)

bp = tk.Button(f2, text='Practice')
bp.grid(row=3, column=0)

bt = tk.Button(f2, text='Test')
bt.grid(row=4, column=0)

bm = tk.Button(f2, text='Test Messgae',
               command=lambda: Text_update(msg, directory, w1))
bm.grid(row=6, column=0)

msg = tk.Text(f2, height=3)
msg.grid(row=5, column=0, columnspan=3)

w1.mainloop()

# # load window
#
#
# def create_window():
#     w11 = tk.Toplevel(root)
#     w11e = tk.Entry(w11)
#     w11e.grid(row=0, column=0)
#     w11e.insert(0, 1)
#     l.insert(0, w11e.get())
#
#
# root = tk.Tk()
# b = tk.Button(root, text="Create new window", command=create_window)
# l = tk.Entry(root)
#
#
# b.pack()
# l.pack()
#
# root.mainloop()

#
# # this is a is work!
# te = tk.Tk()
# sound_icon_ = Image.open("/Users/hao/Documents/dict/icon/sound.png")
# sound_icon_.thumbnail((20, 20), Image.ANTIALIAS)
# sound_icon = ImageTk.PhotoImage(sound_icon_)
#
# b = tk.Button(te, image=sound_icon,  width='30')
#
# b.grid(row=0, column=0)
#
# te.mainloop()

# functions for ADD WORD:
def add_ck():
    if (ck_var.get() == 1):
        for i in range(1, 1 + n_word):
            if len(Text_get(word_d['w' + str(i)])) > 0:
                word_d['ck' + str(i)].select()
    else:
        for i in range(1, 1 + n_word):
            word_d['ck' + str(i)].deselect()

def add_pron(i):
    word = Text_get(word_d['w' + str(i)])
    spelling = pron(word)
    if spelling == False:
        Text_update(addt, word + ' is not found!', wa)
        os.system('say "word is not found"')
    else:
        Text_update(word_d['p' + str(i)], spelling, wa)

def play_pron(i):
    if Text_get(word_d['p' + str(i)]) != "":
        mp3_file = f"/Users/hao/Documents/dict/sound/{Text_get(word_d['w' + str(i)])}.mp3"
        play(AudioSegment.from_mp3(mp3_file))

def add_prons():
    word_na = ''
    for i in range(1, 1 + n_word):
        if word_d['ckv' + str(i)].get() == 1:
            word = Text_get(word_d['w' + str(i)])
            spelling = pron(word)
            if spelling == False:
                word_na += word + ' \n'
            else:
                Text_update(word_d['p' + str(i)], spelling, wa)
    if len(word_na) == 0:
        Text_update(addt, 'all words are found!', wa)
        os.system('say "all words are found"')
    else:
        Text_update(addt, word_na + 'are not found!', wa)
        os.system('say "words are not found"')

def add_check_db():
    cur_window = []
    for i in range(1, 1 + n_word):
        add_check_db_w = Text_get(word_d['w' + str(i)])
        if len(add_check_db_w) > 0:
            if add_check_db_w in wdb['word'].values:
                word_d['in' + str(i)].configure(text='found', bg='red')
            elif add_check_db_w in cur_window:
                word_d['in' + str(i)].configure(text='dup', bg='red')
            else:
                cur_window.append(add_check_db_w)
                word_d['in' + str(i)].configure(text='NEW', bg='green')
        else:
            word_d['in' + str(i)].configure(text='')

def add_delete(i):
    for j in 'wdcjpt':
        word_d[j + str(i)].delete('1.0', tk.END)
    word_d['in' + str(i)].configure(text='', bg='white')
    word_d['ck' + str(i)].deselect()

def add_append():
    # double check the world is not three
    add_append_status = True
    global wdb
    add_check_db()
    for i in range(1, 1 + n_word):
        if len(Text_get(word_d['in' + str(i)])) > 0:
            if word_d['in' + str(i)]["text"] == 'found':
                Text_update(addt, "Already in database!", wa)
                os.system('say "Already in database"')
                add_append_status = False
                break
            if word_d['ckv' + str(i)].get() == 0:
                Text_update(addt, "Not all words are selected", wa)
                os.system('say "Not all words are selected"')
                add_append_status = False
                break
    if add_append_status == True:
        for i in range(1, 1 + n_word):
            new_record = {'word': Text_get(word_d['w' + str(i)]),
                          'definition': Text_get(word_d['d' + str(i)]),
                          'comment': Text_get(word_d['c' + str(i)]),
                          'picture': Text_get(word_d['j' + str(i)]),
                          'pronunciation': Text_get(word_d['p' + str(i)]),
                          'type': Text_get(word_d['t' + str(i)]),
                          'updated_date': date.today().strftime("%Y/%m/%d"),
                          'status': '0'}
            wdb = wdb.append(new_record, ignore_index=True)
    # backup_db() # to enable this later

# add words
def add_words():

    # wa = tk.Toplevel(w1)
    wa = tk.Tk()
    n_word = 10  # int(ea.get())

    tk.Button(wa, text='in_db', command=add_check_db).grid(row=0, column=0)
    tk.Label(wa, text='word', width=5).grid(row=0, column=2)
    tk.Label(wa, text='definition', width=20).grid(row=0, column=3)
    tk.Label(wa, text='comment', width=10).grid(row=0, column=4)
    tk.Label(wa, text='picture', width=5).grid(row=0, column=5)
    tk.Label(wa, text='pronunciation', width=10).grid(row=0, column=6)
    tk.Label(wa, text='type', width=5).grid(row=0, column=8)
    ck_var = tk.IntVar()
    tk.Checkbutton(wa, variable=ck_var, command=add_ck).grid(row=0, column=9)
    tk.Button(wa, text='ALL', command=add_prons).grid(row=0, column=10)

    word_d = {}
    sound_icon = ImageTk.PhotoImage(sound_icon_)
    for i in range(1, 1 + n_word):
        # in_db
        word_d['in' + str(i)] = tk.Label(wa, width=5)
        word_d['in' + str(i)].grid(row=i, column=0, padx=1, pady=1)
        # delete button
        word_d['e' + str(i)] = tk.Button(wa, text='-', width=2,
                                         command=lambda jj=i: add_delete(str(jj)))
        word_d['e' + str(i)].grid(row=i, column=1, padx=1, pady=1)
        # word
        word_d['w' + str(i)] = Text_new(wa, 10)
        word_d['w' + str(i)].grid(row=i, column=2, padx=1, pady=1)
        # definition
        word_d['d' + str(i)] = Text_new(wa, 50)
        word_d['d' + str(i)].grid(row=i, column=3, padx=1, pady=1)
        # comment
        word_d['c' + str(i)] = Text_new(wa, 20)
        word_d['c' + str(i)].grid(row=i, column=4, padx=1, pady=1)
        # picture (jpeg)
        word_d['j' + str(i)] = Text_new(wa, 10)
        word_d['j' + str(i)].grid(row=i, column=5, padx=1, pady=1)
        # pronunciation
        word_d['p' + str(i)] = Text_new(wa, 20)
        word_d['p' + str(i)].grid(row=i, column=6, padx=1, pady=1)
        # play icon
        word_d['s' + str(i)] = tk.Button(wa, image=sound_icon, width=20,
                                         command=lambda jj=i: play_pron(str(jj)))
        word_d['s' + str(i)].grid(row=i, column=7, padx=1, pady=1)
        # type
        word_d['t' + str(i)] = Text_new(wa, 10)
        word_d['t' + str(i)].grid(row=i, column=8, padx=1, pady=1)
        # check box (ckv: check value)
        word_d['ckv' + str(i)] = tk.IntVar()
        word_d['ck' + str(i)] = tk.Checkbutton(wa, var=word_d['ckv' + str(i)])
        word_d['ck' + str(i)].grid(row=i, column=9, padx=1, pady=1)
        # all / get box
        word_d['b' + str(i)] = tk.Button(wa, text='get',
                                         command=lambda jj=i: add_pron(str(jj)))
        word_d['b' + str(i)].grid(row=i, column=10, padx=1, pady=1)

    # append button
    addt = Text_new(wa, 120, 5)
    addt.grid(row=1 + n_word, column=0, columnspan=7)
    addb = tk.Button(wa, command=add_append, text='APPEND', height=2)
    addb.grid(row=1 + n_word, column=8, columnspan=2)
    wa.mainloop()

wdb


import csv
import datetime

import django.contrib.admin
import django.db.models
import django.http

from django.utils.translation import gettext_lazy as _

def export_data_to_csv(
    model_admin: django.contrib.admin.ModelAdmin,
    request: django.http.HttpRequest,
    queryset: django.db.models.QuerySet,
) -> django.http.HttpResponse:
    """экспортируем данные модели в формат csv"""
    options = model_admin.model._meta
    content_disposition = f'attachment; filename="{options.verbose_name}.csv"'
    response = django.http.HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = content_disposition
    writer = csv.writer(response)
    fields = [
        field
        for field in options.get_fields()
        if not field.many_to_many and not field.one_to_many
    ]
    writer.writerow([field.verbose_name for field in fields])
    for obj in queryset:
        data_row = []
        for field in fields:
            value = getattr(obj, field.name)
            if isinstance(value, datetime.datetime):
                value = value.strftime('%Y.%m.%d')
            data_row.append(value)
        writer.writerow(data_row)
    return response

export_data_to_csv.short_description = _('export to csv')


from discord.ext import commands
from datetime import datetime as d
from discord.ext.commands import has_permissions, CheckFailure

class Moderation(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
    @commands.command(
        name='mutechat',
        description='mutes the channel',
        help ="Mutes the channel"
    )
    @commands.has_permissions(manage_channels=True)
    async def mutechat(self, ctx):
        await ctx.send("``` Muting Chat ```")
        await ctx.channel.set_permissions(ctx.guild.default_role, send_messages=False)
        await ctx.send("``` Muted Chat! ```")
    #mutechat error
    @mutechat.error
    async def mutechat_error(self, ctx, error):
        if isinstance(error, commands.MissingPermissions):
            text = f"Sorry {ctx.author}, you do not have permission to do that!"
            await ctx.send (text)

    @commands.command(
        name='unmutechat',
        description='unmutes the channel',
        help ="Unmutes the channel"
    )
    @commands.has_permissions(manage_channels=True)
    async def unmutechat(self, ctx):
        await ctx.send("``` Unmuting Chat ```")
        await ctx.channel.set_permissions(ctx.guild.default_role, send_messages=True)
        await ctx.send("``` Unmted Chat! ```")
    @unmutechat.error
    async def unmutechat_error(self, ctx, error):
        if isinstance(error, commands.MissingPermissions):
            text = f"Sorry {ctx.author}, you do not have permission to do that!"
            await ctx.send (text)

def setup(bot):
    bot.add_cog(Moderation(bot))


import pytest
import subprocess
import rospy
import time

# conftest.py is a special file that pytest will
# load and make available for all other tests in this directory

@pytest.fixture(scope="module")
def roscore():
    """
    Starts a roscore in a background process.
    Stops it once the tests are done.
    """
    try:
        process = subprocess.Popen("roscore")
        wait_for_roscore_to_be_running(2)
        yield
    finally:
        process.terminate()
        process.wait()

def wait_for_roscore_to_be_running(timeout):

    start_time = time.time()

    while time.time() - start_time < timeout:
        try:
            # Fails if roscore is not running
            rospy.get_published_topics()

            # Roscore must be running to get here
            return
        except:
            time.sleep(0.01)

    raise Exception("roscore not running")


import os
import sys
import cv2
import requests
import utils as u

def main():

    args_1: str = "--mode"
    args_2: str = "--base-url"
    args_3: str = "--li"
    args_4: str = "--filename-1"
    args_5: str = "--filename-2"

    mode: str = "remove"
    base_url: str = "http://localhost:3030"
    lightweight: bool = False
    filename_1: str = "Test_1.jpg"
    filename_2: str = "Test_2.jpg"

    if args_1 in sys.argv: mode: str = sys.argv[sys.argv.index(args_1) + 1]
    if args_2 in sys.argv: base_url: str = sys.argv[sys.argv.index(args_2) + 1]
    if args_3 in sys.argv: lightweight = True
    if args_4 in sys.argv: filename_1: str = sys.argv[sys.argv.index(args_4) + 1]
    if args_5 in sys.argv: filename_2: str = sys.argv[sys.argv.index(args_5) + 1]

    if not lightweight:
        url: str = base_url + f"/{mode}"
    else:
        url: str = base_url + f"/{mode}" + "/li"

    assert filename_1 in os.listdir(u.INPUT_PATH), f"{filename_1} not found in input directory"

    image = cv2.imread(os.path.join(u.INPUT_PATH, filename_1))

    payload = {
        "imageData_1" : u.encode_image_to_base64(image=image)
    }

    if mode == "remove":
        response = requests.request(method="POST", url=url, json=payload)
        if response.status_code == 200 and response.json()["statusCode"] == 200:
            u.show_images(
                image_1=cv2.cvtColor(src=image, code=cv2.COLOR_BGR2RGB),
                image_2=cv2.cvtColor(src=u.decode_image(response.json()["bglessImageData"]), code=cv2.COLOR_BGR2RGB),
                cmap_1="gnuplot2",
                cmap_2="gnuplot2",
                title_1="Original",
                title_2="BG Removed Image",
            )
        else:
            print(f"Error {response.status_code} : {response.reason}")

    elif mode == "replace":
        assert filename_2 in os.listdir(u.INPUT_PATH), f"{filename_2} not found in input directory"

        image_2 = cv2.imread(os.path.join(u.INPUT_PATH, "Test_2.jpg"))

        payload = {
            "imageData_1" : u.encode_image_to_base64(image=image),
            "imageData_2" : u.encode_image_to_base64(image=image_2)
        }

        response = requests.request(method="POST", url=url, json=payload)

        if response.status_code == 200 and response.json()["statusCode"] == 200:
            u.show_images(
                image_1=cv2.cvtColor(src=image, code=cv2.COLOR_BGR2RGB),
                image_2=cv2.cvtColor(src=u.decode_image(response.json()["bgreplaceImageData"]), code=cv2.COLOR_BGR2RGB),
                cmap_1="gnuplot2",
                cmap_2="gnuplot2",
                title_1="Original",
                title_2="BG Replaced Image",
            )
        else:
            print(f"Error {response.status_code} : {response.reason}")

if __name__ == "__main__":
    sys.exit(main() or 0)


from __future__ import annotations

import argparse
import logging
import typing
from dataclasses import dataclass
from pathlib import Path
from typing import List, Optional, Sequence, TypedDict

import configpile as cp
import numpy as np
import numpy.typing as npt
import tybles as tb
from filelock import FileLock
from numpy.typing import NDArray
from scipy.interpolate import interp1d
from typing_extensions import Annotated

from ..lib.analysis import find_nearest1
from ..lib.data import LoggingLevel, PickleProtocol
from ..lib.io import open_pickle, save_pickle
from ..lib.math import absurd_minus_99_9, create_grid, doppler_r
from ..lib.util import log_task_name_and_time
from .data import (
    IndividualImportedRow,
    IndividualReinterpolatedRow,
    PickledIndividualSpectrum,
    ReinterpolatedSpectrumPickle,
)

@dataclass(frozen=True)
class Task(cp.Config):
    """Reinterpolates the spectra to match the stellar frame"""

    #
    # Common information
    #

    prog_ = Path(__file__).stem
    ini_strict_sections_ = [Path(__file__).stem]
    ini_relaxed_sections_ = [Path(__file__).stem.split("_")[0]]
    env_prefix_ = "RASSINE"

    #: Use the specified configuration files.
    #:
    #: Files can be separated by commas/the command can be invoked multiple times.
    config: Annotated[Sequence[Path], cp.Param.config(env_var_name="RASSINE_CONFIG")]

    #: Root path of the data, used as a base for other relative paths
    root: Annotated[Path, cp.Param.root_path(env_var_name="RASSINE_ROOT")]

    #: Pickle protocol version to use
    pickle_protocol: Annotated[
        PickleProtocol, cp.Param.store(PickleProtocol.parser(), default_value="3")
    ]

    #: Logging level to use
    logging_level: Annotated[
        LoggingLevel,
        cp.Param.store(
            LoggingLevel.parser(), default_value="WARNING", env_var_name="RASSINE_LOGGING_LEVEL"
        ),
    ]

    #
    # Task specific information
    #

    #: Input spectrum table
    input_table: Annotated[Path, cp.Param.store(cp.parsers.path_parser, short_flag_name="-I")]

    #: Output spectrum table
    output_table: Annotated[Path, cp.Param.store(cp.parsers.path_parser, short_flag_name="-O")]

    #: Relative path to the folder containing the spectra
    input_folder: Annotated[Path, cp.Param.store(cp.parsers.path_parser, short_flag_name="-i")]

    #: Name of the output directory. If None, the output directory is created at the same location than the spectra.
    output_folder: Annotated[Path, cp.Param.store(cp.parsers.path_parser, short_flag_name="-o")]

    #: Indices of spectrum to process
    #:
    #: If not provided, all spectra are processed
    inputs: Annotated[
        Sequence[int],
        cp.Param.append1(
            cp.parsers.int_parser,
            positional=cp.Positional.ZERO_OR_MORE,
            long_flag_name=None,
            short_flag_name=None,
        ),
    ]

    #: Wavelength step in angstrom used to produce the equidistant wavelength vector
    dlambda: Annotated[float, cp.Param.store(cp.parsers.float_parser)]

    def validate_output_folder(self) -> Optional[cp.Err]:
        return cp.Err.check(
            (self.root / self.output_folder).is_dir(), "The output directory needs to exist"
        )

@dataclass(frozen=True)
class ReinterpolationSettings:
    wave_min_k: np.float64
    wave_max_k: np.float64
    hole_left_k: np.float64
    hole_right_k: np.float64
    dlambda: np.float64
    nb_bins: int
    static_grid: NDArray[np.float64]
    wave_ref: int

    @staticmethod
    def make(
        wave_min_k: np.float64,
        wave_max_k: np.float64,
        hole_left_k: np.float64,
        hole_right_k: np.float64,
        dlambda: np.float64,
        nb_bins: int,
    ) -> ReinterpolationSettings:
        static_grid = create_grid(wave_min_k, dlambda, nb_bins)
        wave_ref = find_nearest1(static_grid, 5500)[0]
        return ReinterpolationSettings(
            wave_min_k=wave_min_k,
            wave_max_k=wave_max_k,
            hole_left_k=hole_left_k,
            hole_right_k=hole_right_k,
            dlambda=dlambda,
            nb_bins=nb_bins,
            static_grid=static_grid,
            wave_ref=wave_ref,
        )

    @staticmethod
    def from_spectrum_data(
        wave_min: NDArray[np.float64],
        wave_max: NDArray[np.float64],
        hole_left: NDArray[np.float64],
        hole_right: NDArray[np.float64],
        dlambda: np.float64,
    ) -> ReinterpolationSettings:
        hole_left = hole_left[hole_left != absurd_minus_99_9]
        hole_right = hole_right[hole_right != absurd_minus_99_9]

        if len(hole_left) != 0 and len(hole_right) != 0:
            hole_left_k = np.min(hole_left) - 0.5  # increase of 0.5 the gap limit by security
            hole_right_k = np.max(hole_right) + 0.5  # increase of 0.5 the gap limit by security
        else:
            hole_left_k = absurd_minus_99_9
            hole_right_k = absurd_minus_99_9
        wave_min_k = wave_min.max()
        wave_max_k = wave_max.min()
        nb_bins: int = int(np.ceil((wave_max_k - wave_min_k) / dlambda))
        return ReinterpolationSettings.make(
            wave_min_k=wave_min_k,
            wave_max_k=wave_max_k,
            hole_left_k=np.float64(hole_left_k),
            hole_right_k=np.float64(hole_right_k),
            dlambda=dlambda,
            nb_bins=nb_bins,
        )

def reinterpolate(
    t: Task, row: IndividualImportedRow, s: ReinterpolationSettings
) -> IndividualReinterpolatedRow:
    input_file = t.root / t.input_folder / (row.name + ".p")
    output_file = t.root / t.output_folder / (row.name + ".p")
    spectrum = open_pickle(input_file, PickledIndividualSpectrum)

    # raw spectrum
    wave = spectrum["wave"]
    flux = spectrum["flux"]
    flux_err = spectrum["flux_err"]

    # reinterpolated using static_grid
    static_grid = s.static_grid
    new_flux = interp1d(
        doppler_r(wave, row.rv_shift)[1],
        flux,
        kind="cubic",
        bounds_error=False,
        fill_value="extrapolate",
    )(static_grid)
    new_flux_err = interp1d(
        doppler_r(wave, row.rv_shift)[1],
        flux_err,
        kind="linear",
        bounds_error=False,
        fill_value="extrapolate",
    )(static_grid)

    mask2 = (static_grid >= (s.hole_left_k - s.dlambda / 2.0)) & (
        static_grid <= (s.hole_right_k + s.dlambda / 2.0)
    )
    new_flux[mask2] = 0
    new_flux_err[mask2] = 1

    continuum_5500 = np.nanpercentile(new_flux[s.wave_ref - 50 : s.wave_ref + 50], 95)
    SNR = np.sqrt(continuum_5500)

    out: ReinterpolatedSpectrumPickle = {
        "flux": new_flux,
        "flux_err": new_flux_err,
        "RV_sys": row.rv_mean,
        "RV_shift": row.rv_shift,
        "SNR_5500": SNR,
        "berv": row.berv,
        "lamp_offset": row.lamp_offset,
        "plx_mas": row.plx_mas,
        "acc_sec": row.acc_sec,
        "instrument": row.instrument,
        "mjd": row.mjd,
        "jdb": row.jdb,
        "hole_left": s.hole_left_k,
        "hole_right": s.hole_right_k,
        "wave_min": s.wave_min_k,
        "wave_max": s.wave_max_k,
        "dwave": s.dlambda,
    }
    save_pickle(output_file, out)
    return IndividualReinterpolatedRow(
        name=row.name,
        instrument=row.instrument,
        mjd=row.mjd,
        jdb=row.jdb,
        model=row.model,
        rv_mean=row.rv_mean,
        rv_shift=row.rv_shift,
        SNR_5500=SNR,
        berv=row.berv,
        lamp_offset=row.lamp_offset,
        plx_mas=row.plx_mas,
        acc_sec=row.acc_sec,
        wave_min=s.wave_min_k,
        wave_max=s.wave_max_k,
        dwave=s.dlambda,
        nb_bins=np.int64(s.nb_bins),
        hole_left=s.hole_left_k,
        hole_right=s.hole_right_k,
        vrad=row.vrad,
        svrad=row.svrad,
        drift=row.drift,
    )

def get_parser() -> argparse.ArgumentParser:
    """Returns the argument parser for Sphinx doc purposes"""
    return Task.get_argument_parser_()

@log_task_name_and_time(name=Path(__file__).stem)
def run(t: Task) -> None:
    t.logging_level.set()
    t.pickle_protocol.set()
    (t.root / t.output_folder).mkdir(parents=True, exist_ok=True)
    (t.root / t.output_table).parent.mkdir(parents=True, exist_ok=True)

    logging.debug(f"Reading {t.root/t.input_table}")
    tyble = IndividualImportedRow.schema().read_csv(t.root / t.input_table, return_type="Tyble")
    df = tyble.data_frame

    # compute hole boundaries
    settings = ReinterpolationSettings.from_spectrum_data(
        wave_min=np.round(df["wave_min"].to_numpy(), 8).astype(
            np.float64
        ),  # to take into account float32
        wave_max=np.round(df["wave_max"].to_numpy(), 8).astype(
            np.float64
        ),  # to take into account float32
        hole_left=df["hole_left"].to_numpy(),
        hole_right=df["hole_right"].to_numpy(),
        dlambda=np.float64(t.dlambda),
    )

    inputs: Sequence[int] = t.inputs
    if not inputs:
        inputs = list(range(len(df)))

    output_rows: List[IndividualReinterpolatedRow] = []
    for i in inputs:
        r = tyble[i]
        output_rows.append(reinterpolate(t, r, settings))

    output_table = t.root / t.output_table
    output_table_lockfile = output_table.with_suffix(output_table.suffix + ".lock")

    logging.debug(f"Appending to output table {output_table}")
    with FileLock(output_table_lockfile):
        df = IndividualReinterpolatedRow.schema().from_rows(output_rows, return_type="DataFrame")
        df.to_csv(output_table, header=not output_table.exists(), mode="a", index=False)

def cli() -> None:
    run(Task.from_command_line_())


# This program is free software: you can redistribute it and/or modify it under the
# terms of the Apache License (v2.0) as published by the Apache Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the Apache License for more details.
#
# You should have received a copy of the Apache License along with this program.
# If not, see <https://www.apache.org/licenses/LICENSE-2.0>.

"""Level unit tests."""

# standard libs
from string import ascii_letters

# internal libs
from logalpha.level import Level, LEVELS, DEBUG, INFO, WARNING, ERROR, CRITICAL

# external libs
from hypothesis import given, assume, strategies as st

@given(st.text(ascii_letters, max_size=10), st.integers(min_value=0, max_value=10))
def test_init(name: str, value: int) -> None:
    """Check initialization."""
    level = Level(name=name, value=value)
    assert level.name == name
    assert level.value == value

@given(st.integers(min_value=0, max_value=10), st.integers(min_value=0, max_value=10))
def test_comparison(a: int, b: int) -> None:
    """Test level comparisons."""
    assume(a < b)
    assert Level(name='A', value=a) < Level(name='B', value=b)

def test_standard_levels() -> None:
    """Test default levels."""
    levels = [DEBUG, INFO, WARNING, ERROR, CRITICAL]
    for i, level in enumerate(levels):
        assert LEVELS[i] is level
        for lower_level in LEVELS[:i]:
            assert lower_level < level

def test_from_names() -> None:
    """Check .from_names factory method."""
    names = ['A', 'B', 'C', 'D', 'F']
    levels = Level.from_names(names)
    for i, level in enumerate(levels):
        assert level.name == names[i]
        assert level.value == i