import random
import pygame

pygame.init()

display_width = 800
display_height = 600

display = pygame.display.set_mode((display_width, display_height))
pygame.display.set_caption('Poker')

icon = pygame.image.load('icon.png')
pygame.display.set_icon(icon)

bank = 0
Max_points = 0
Player1_points = 0
Player2_points = 0

clock = pygame.time.Clock()
current_time = 0

need_input = False
input_text = '|'
input_tick = 30

player_name = ''

class Card:
    def __init__(self, val, suit, image, x, y, points, set):
        self.val = val
        self.suit = suit
        self.image = image
        self.x = x
        self.y = y
        self.points = points
        self.set = set

    def __repr__(self):
        return repr(self.val + ' ' + self.suit)

class Button:
    def __init__(self, width, height):
        self.width = width
        self.height = height
        self.inactive_color = (142, 142, 142)
        self.active_color = (195, 195, 195)
        self.active = False

    def draw(self, x, y, message, action, font_color=(0, 0, 0), font_size=30, h=0, w=0):
        mouse = pygame.mouse.get_pos()
        click = pygame.mouse.get_pressed(3)

        if x < mouse[0] < x + self.width and y < mouse[1] < y + self.height:
            pygame.draw.rect(display, self.active_color, (x, y, self.width, self.height))

            if click[0] == 1:
                if action is not None:
                    self.active = True
                    if action == quit:
                        pygame.quit()
                        quit()
                    else:
                        action()
                        self.active = False

        else:
            pygame.draw.rect(display, self.inactive_color, (x, y, self.width, self.height))

        output_text(message=message, x=x + w, y=y + h, font_color=font_color, font_size = font_size)

Card_values = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'Jack', 'Queen', 'King', 'Ace']
Card_suits = ['Clubs', 'Diamonds', 'Hearts', 'Spades']
Cards_img = pygame.image.load('Cards.png')
Combination = {'High card': 1, 'Pair': 2, 'Two pair': 3, 'Three of a Kind': 4, 'Straight': 5, 'Flush': 6, 'Full House': 7, 'Four of a Kind': 8, 'Straight-flush': 9, 'Royal Flush': 10}
results = {'p1': 0, 'p1 points': 0, 'p2': 0, 'p2 points': 0}

def show_menu():
    menu_background = pygame.image.load('Menu_background.png')

    settings_btn = Button(190, 80)
    quit_btn = Button(190, 80)

    show = True
    while show:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        display.blit(menu_background, (0, 0))
        settings_btn.draw(display_width/2 - 190/2, display_height/2 - 65, 'Играть', settings, (0, 0, 0), 50, 10, 20)
        quit_btn.draw(display_width/2 - 190/2, display_height/2 + 40, 'Выход', quit, (0, 0, 0), 50, 10, 20)

        pygame.display.update()
        clock.tick(60)

def start_game():
    if Max_points > 0:
        while game_cycle():
            pass

def game_cycle():

    global Player1_cards
    global Player2_cards
    global Table_cards
    global Cards
    global Player1_points
    Cards = []

    run = True
    background = pygame.image.load('Table.png')

    for i in range(len(Card_values)):
        for j in range(len(Card_suits)):
            rect = (80 * i, 120 * j, 80, 120)
            img = Cards_img.subsurface(rect)
            Cards.append(Card(Card_values[i], Card_suits[j], img, 0, 0, i + 2, ''))

    Player1_cards = create_set('p1')
    Player2_cards = create_set('p2')
    Table_cards = create_set('t')

    output(Player1_cards, Player2_cards, Table_cards)

    while run:

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        display.blit(background, (0, 0))
        draw_players_cards()
        draw_table_cards()

        output_text(str(Player1_points), 10, 560, (0, 0, 0))
        output_text(str(Player2_points), 10, 10, (0, 0, 0))
        output_text('Банк: ' + str(bank), 10, 275, (0, 0, 0))
        output_text(player_name, 55, 480, (255, 255, 255), font_size=35)

        auction()

        pygame.display.update()

        if len(Table_cards) == 5:
            pygame.time.wait(10000)
            if Player1_points == 0 or Player2_points == 0:
                run = False
            else:
                start_game()

    return end_game()

def settings():

    bckgrnd = pygame.image.load('settings_bg.png')
    settings = True

    global plus_100_btn
    global plus_200_btn
    global plus_500_btn
    global plus_1000_btn
    global  plus_2000_btn

    global minus_100_btn
    global minus_200_btn
    global minus_500_btn
    global minus_1000_btn
    global minus_2000_btn

    global equally_0_btn

    plus_100_btn = Button(90, 40)
    plus_200_btn = Button(90, 40)
    plus_500_btn = Button(90, 40)
    plus_1000_btn = Button(90, 40)
    plus_2000_btn = Button(90, 40)

    minus_100_btn = Button(90, 40)
    minus_200_btn = Button(90, 40)
    minus_500_btn = Button(90, 40)
    minus_1000_btn = Button(90, 40)
    minus_2000_btn = Button(90, 40)

    equally_0_btn = Button(60, 40)
    start_btn = Button(130, 50)

    while settings:

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        display.blit(bckgrnd, (0, 0))

        output_text('Введите ваше имя и нажмите Enter', 175, 300, (50, 50, 50), font_size=30)
        output_text('Ваше имя: ' + player_name, 175, 430, (50, 50, 50), font_size=30)
        output_text('Количество очков у игрока: ' + str(Max_points), 150, 30, (0, 0, 0), font_size=40)

        plus_100_btn.draw(90, 100, '+ 100', setting, (0, 0, 0), 20, 10, 20)
        plus_200_btn.draw(200, 100, '+ 200', setting, (0, 0, 0), 20, 10, 20)
        plus_500_btn.draw(310, 100, '+ 500', setting, (0, 0, 0), 20, 10, 20)
        plus_1000_btn.draw(420, 100, '+ 1000', setting, (0, 0, 0), 20, 10, 20)
        plus_2000_btn.draw(530, 100, '+ 2000', setting, (0, 0, 0), 20, 10, 20)

        minus_100_btn.draw(90, 170, '- 100', setting, (0, 0, 0), 20, 10, 20)
        minus_200_btn.draw(200, 170, '- 200', setting, (0, 0, 0), 20, 10, 20)
        minus_500_btn.draw(310, 170, '- 500', setting, (0, 0, 0), 20, 10, 20)
        minus_1000_btn.draw(420, 170, '- 1000', setting, (0, 0, 0), 20, 10, 20)
        minus_2000_btn.draw(530, 170, '- 2000', setting, (0, 0, 0), 20, 10, 20)

        equally_0_btn.draw(660, 135, '= 0', setting, (0, 0, 0), 20, 10, 20)

        start_btn.draw(660, 540, 'Начать', start_game, (0, 0, 0), h=10, w=20)

        get_input()

        pygame.display.update()

def auction():

    pygame.time.wait(1000)

    global run_auction
    global bet
    global plus_10_btn
    global minus_10_btn
    global all_in_btn
    global time

    run_auction = True

    bet = 0

    create_bet = Button(90, 35)
    plus_10_btn = Button(40, 40)
    minus_10_btn = Button(40, 40)
    all_in_btn = Button(80, 35)
    check_btn = Button(80, 35)

    while run_auction:

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        pygame.draw.rect(display, (255, 255, 255), (670, 430, 70, 40))

        output_text(str(bet), 675, 435, (0, 0, 0))

        if Player1_points > 0:
            create_bet.draw(660, 480, 'сделать', end_auction, (0, 0, 0), 15, w=20)
            output_text('ставку', 683, 495, (0, 0, 0), font_size=15)
            minus_10_btn.draw(620, 430, '-10', calculate, font_size=20, h=10, w=5)
            plus_10_btn.draw(750, 430, '+10', calculate, font_size=20, h=10, w=5)
            all_in_btn.draw(620, 550, 'Ва-банк', calculate, (0, 0, 0), 15, h=10, w=12)
        else:
            create_bet.draw(660, 480, 'сделать', None, (0, 0, 0), 15, w=20)
            output_text('ставку', 683, 495, (0, 0, 0), font_size=15)
            minus_10_btn.draw(620, 430, '-10', None, font_size=20, h=10, w=5)
            plus_10_btn.draw(750, 430, '+10', None, font_size=20, h=10, w=5)
            all_in_btn.draw(620, 550, 'Ва-банк', None, (0, 0, 0), 15, h=10, w=12)

        check_btn.draw(710, 550, 'Чек', end_auction, (0, 0, 0), 15, h=10, w=25)

        pygame.display.update()

def calculate():

    global bet

    if plus_10_btn.active and bet < Player1_points:
        bet += 10

    if minus_10_btn.active and bet > 0:
        bet -= 10

    if all_in_btn.active:
        bet = Player1_points
        end_auction()

    pygame.time.wait(300)

def end_auction():

    global run_auction
    global bank
    global Player1_points

    bank += bet
    Player1_points -= bet

    if bet > 0:
        output_text('-' + str(bet), 80, 560, (0, 0, 0))

    run_auction = False
    pygame.time.wait(5000)
    new_card()

def setting():

    global Max_points
    global Player1_points
    global Player2_points

    if plus_100_btn.active == True:
        Max_points += 100

    elif plus_200_btn.active == True:
        Max_points += 200

    elif plus_500_btn.active == True:
        Max_points += 500

    elif plus_1000_btn.active == True:
        Max_points += 1000

    elif plus_2000_btn.active == True:
        Max_points += 2000

    elif minus_100_btn.active == True and Max_points - 100 >= 0:
        Max_points -= 100

    elif minus_200_btn.active == True and Max_points - 200 >= 0:
        Max_points -= 200

    elif minus_500_btn.active == True and Max_points - 500 >= 0:
        Max_points -= 500

    elif minus_1000_btn.active == True and Max_points - 1000 >= 0:
        Max_points -= 1000

    elif minus_2000_btn.active == True and Max_points - 2000 >= 0:
        Max_points -= 2000

    elif equally_0_btn.active == True:
        Max_points = 0

    Player1_points = Max_points
    Player2_points = Max_points

    pygame.time.wait(300)

def get_input():
    global input_text, need_input, player_name, input_tick

    input_rect = pygame.Rect(225, 350, 350, 60)

    pygame.draw.rect(display, (255, 255, 255), input_rect)

    mouse = pygame.mouse.get_pos()
    click = pygame.mouse.get_pressed(3)

    if input_rect.collidepoint(mouse[0], mouse[1]) and click[0]:
        need_input = True

    if need_input:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

            if need_input and event.type == pygame.KEYDOWN:
                input_text = input_text.replace('|', '')
                input_tick = 30

                if event.key == pygame.K_RETURN:
                    need_input = False
                    player_name = input_text
                    input_text = ''
                    print(player_name)
                elif event.key == pygame.K_BACKSPACE:
                    input_text = input_text[:-1]
                else:
                    if len(input_text) < 10:
                        input_text += event.unicode

                input_text += '|'

    if len(input_text):
        output_text(input_text, input_rect.x + 10, input_rect.y + 10, (0, 0, 0), font_size=40)

    input_tick -= 1

    if input_tick == 0:
        input_text = input_text[:-1]
    if input_tick == -30:
        input_text += '|'
        input_tick = 30

def rand_card():
    choice = random.randrange(0, len(Cards))
    card = Cards[choice]
    del Cards[choice]
    return card

def create_set(a):
    mass = []
    for i in range(2):
        card = rand_card()
        card.set = a
        mass.append(card)
    return mass

def new_card():
    card = rand_card()
    card.set = 't'
    Table_cards.append(card)
    print(repr(Table_cards[-1]))
    display.blit(Table_cards[-1].image,(Table_cards[-2].x - 100, Table_cards[-2].y))

def output(Player1_cards, Player2_cards, Table_cards):
    print('Player1: ', end="")
    for i in range(0, len(Player1_cards)):
        print('|' + repr(Player1_cards[i]) + '| ', end="")

    print('\n', 'Table: ', end="", sep="")
    for i in range(0, len(Table_cards)):
        print('|' + repr(Table_cards[i]) + '| ', end="")

    print('\n', 'Player2: ', end="", sep="")
    for i in range(0, len(Player2_cards)):
        print('|' + repr(Player2_cards[i]) + '| ', end="")

    print('\n')

def draw_players_cards():
    for i in range(2):
        display.blit(Player1_cards[i].image, ((display_width/2)-90+100*i, 470))
        Player1_cards[i].x = (display_width/2)-90+100*i
        Player1_cards[i].y = 470
        display.blit(Player2_cards[i].image, ((display_width/2)-90+100*i, 10))
        Player2_cards[i].x = (display_width/2)-90+100*i
        Player2_cards[i].y = 10

def draw_table_cards():
    for i in range(len(Table_cards)):
        display.blit(Table_cards[i].image, ((display_width / 2) + 160 - 100 * i, (display_height / 2) - 60))
        Table_cards[i].x = (display_width / 2) + 160 - 100 * i
        Table_cards[i].y = (display_height / 2) - 60

def new_mass(mass1, mass2):
    Mass = []
    for i in range(len(mass1)):
        Mass.append(mass1[i])

    for i in range(len(mass2)):
        Mass.append(mass2[i])

    sorted_mass = sort_mass(Mass)
    return sorted_mass

def sort_mass(Tab_and_p):
    for i in range(len(Tab_and_p) - 1):
        for j in range(len(Tab_and_p) - i - 1):
            if Tab_and_p[j].points > Tab_and_p[j + 1].points:
                Tab_and_p[j], Tab_and_p[j + 1] = Tab_and_p[j + 1], Tab_and_p[j]

    print('\n')
    for i in range(len(Tab_and_p)):
        print(repr(Tab_and_p[i]) + ' ')

    return Tab_and_p

def check(Player_cards, Table_cards):

    global results
    Tab_and_p = new_mass(Player_cards, Table_cards)

#Алгоритм поиска Старшей карты
    for i in range(-1, -1*len(Tab_and_p), -1):
        if (Tab_and_p[i].set != 't'):
            if (Player_cards == Player1_cards):
                results['p1'] = Combination['High card']
                results['p1 points'] = Tab_and_p[i].points
            elif (Player_cards == Player2_cards):
                results['p2'] = Combination['High card']
                results['p2 points'] = Tab_and_p[i].points
            print('Старшая карта')
            break

#Алгоритм поиска Пары карт
    for i in range(1, len(Tab_and_p)):
        if (Tab_and_p[i].val == Tab_and_p[i-1].val and Tab_and_p[i].set != Tab_and_p[i-1].set):
            if (Player_cards == Player1_cards):
                results['p1'] = Combination['Pair']
                results['p1 points'] = (Tab_and_p[i].points + Tab_and_p[i-1].points)
            elif (Player_cards == Player2_cards):
                results['p2'] = Combination['Pair']
                results['p2 points'] = (Tab_and_p[i].points + Tab_and_p[i-1].points)
            print('Пара')
            break

#Алгоритм поиска Двух Пар карт
    for i in range(1, len(Tab_and_p)):
        if (Tab_and_p[i].val == Tab_and_p[i-1].val and Tab_and_p[i].set != Tab_and_p[i-1].set):
            for j in range(i+2, len(Tab_and_p)):
                if (Tab_and_p[j].val == Tab_and_p[j - 1].val and Tab_and_p[j].set != Tab_and_p[j - 1].set):
                    if (Player_cards == Player1_cards):
                        results['p1'] = Combination['Two pair']
                        results['p1 points'] = Tab_and_p[j].points + Tab_and_p[j-1].points + Tab_and_p[i].points + Tab_and_p[i-1].points
                    elif (Player_cards == Player2_cards):
                        results['p2'] = Combination['Two pair']
                        results['p2 points'] += Tab_and_p[j].points + Tab_and_p[j-1].points + Tab_and_p[i].points + Tab_and_p[i-1].points
                print('Две Пары')
            break

#Алгоритм поиска Тройки(Сета)
    for i in range(2, len(Tab_and_p)):
        if ((Tab_and_p[i].val == Tab_and_p[i - 1].val and Tab_and_p[i].val == Tab_and_p[i - 2].val) and (Tab_and_p[i].set != 't' or Tab_and_p[i-1].set != 't' or Tab_and_p[i-2].set != 't')):
            if (Player_cards == Player1_cards):
                results['p1'] = Combination['Three of a Kind']
                results['p1 points'] = Tab_and_p[i].points + Tab_and_p[i-1].points + Tab_and_p[i-2].points
            elif (Player_cards == Player2_cards):
                results['p2'] = Combination['Three of a Kind']
                results['p2 points'] = Tab_and_p[i].points + Tab_and_p[i-1].points + Tab_and_p[i-2].points
            print('Тройка')

#Алгоритм поиска Стрита
    for i in range(4, len(Tab_and_p)):
        if ((Tab_and_p[i].points == Tab_and_p[i-1].points + 1) and (Tab_and_p[i].points == Tab_and_p[i-2].points + 2) and (Tab_and_p[i].points == Tab_and_p[i-3].points + 3) and (Tab_and_p[i].points == Tab_and_p[i-4].points + 4) and (Tab_and_p[i].set != 't' or Tab_and_p[i-1].set != 't' or Tab_and_p[i-2].set != 't' or Tab_and_p[i-3].set != 't' or Tab_and_p[i-4].set != 't')):
            if (Player_cards == Player1_cards):
                results['p1'] = Combination['Straight']
                results['p1 points'] = Tab_and_p[i].points + Tab_and_p[i-1].points + Tab_and_p[i-2].points + Tab_and_p[i-3].points + Tab_and_p[i-4].points
            elif (Player_cards == Player2_cards):
                results['p2'] = Combination['Straight']
                results['p2 points'] = Tab_and_p[i].points + Tab_and_p[i-1].points + Tab_and_p[i-2].points + Tab_and_p[i-3].points + Tab_and_p[i-4].points
            print('Стрит')

#Алгоритм поиска Флэша
    for i in range(4, len(Tab_and_p)):
        if ((Tab_and_p[i].suit == Tab_and_p[i-1].suit) and (Tab_and_p[i].suit == Tab_and_p[i-2].suit) and (Tab_and_p[i].suit == Tab_and_p[i-3].suit) and (Tab_and_p[i].suit == Tab_and_p[i-4].suit) and (Tab_and_p[i].set != 't' or Tab_and_p[i-1].set != 't' or Tab_and_p[i-2].set != 't' or Tab_and_p[i-3].set != 't' or Tab_and_p[i-4].set != 't')):
            if (Player_cards == Player1_cards):
                results['p1'] = Combination['Flush']
                results['p1 points'] = Tab_and_p[i].points + Tab_and_p[i-1].points + Tab_and_p[i-2].points + Tab_and_p[i-3].points + Tab_and_p[i-4].points
            elif (Player_cards == Player2_cards):
                results['p2'] = Combination['Flush']
                results['p2 points'] = Tab_and_p[i].points + Tab_and_p[i-1].points + Tab_and_p[i-2].points + Tab_and_p[i-3].points + Tab_and_p[i-4].points
            print('Флэш')

#Алгоритм поиска Фулл Хауса, начиная с Пары
    for i in range(1, len(Tab_and_p)):
        if (Tab_and_p[i].val == Tab_and_p[i-1].val and Tab_and_p[i].set != Tab_and_p[i-1].set):
            if (len(Tab_and_p) - 1 - i > 2):
                for j in range(i+3, len(Tab_and_p)):
                    if ((Tab_and_p[j].val == Tab_and_p[j - 1].val and Tab_and_p[j].val == Tab_and_p[j - 2].val) and (Tab_and_p[j].set != 't' or Tab_and_p[j-1].set != 't' or Tab_and_p[j-2].set != 't')):
                        if (Player_cards == Player1_cards):
                            results['p1'] = Combination['Full House']
                            results['p1 points'] = Tab_and_p[i].points + Tab_and_p[i - 1].points + Tab_and_p[j].points + Tab_and_p[j - 1].points + Tab_and_p[j - 2].points
                        elif (Player_cards == Player2_cards):
                            results['p2'] = Combination['Full House']
                            results['p2 points'] = Tab_and_p[i].points + Tab_and_p[i - 1].points + Tab_and_p[j].points + Tab_and_p[j - 1].points + Tab_and_p[j - 2].points
                        print('Фулл Хаус')

#Алгоритм поиска Фулл Хауса, начиная с Тройки(Сета)
    for i in range(2, len(Tab_and_p)):
        if ((Tab_and_p[i].val == Tab_and_p[i - 1].val and Tab_and_p[i].val == Tab_and_p[i - 2].val) and (Tab_and_p[i].set != 't' or Tab_and_p[i-1].set != 't' or Tab_and_p[i-2].set != 't')):

            if (len(Tab_and_p) - 1 - i > 1):
                for j in range(i+2, len(Tab_and_p)):
                    if (Tab_and_p[j].val == Tab_and_p[j - 1].val and Tab_and_p[j].set != Tab_and_p[j - 1].set):
                        if (Player_cards == Player1_cards):
                            results['p1'] = Combination['Full House']
                            results['p1 points'] = Tab_and_p[j].points + Tab_and_p[j - 1].points + Tab_and_p[i].points + Tab_and_p[i - 1].points + Tab_and_p[i - 2].points
                        elif (Player_cards == Player2_cards):
                            results['p2'] = Combination['Full House']
                            results['p2 points'] = Tab_and_p[j].points + Tab_and_p[j - 1].points + Tab_and_p[i].points + Tab_and_p[i - 1].points + Tab_and_p[i - 2].points
                        print('Фулл Хаус')

#Алгоритм поиска Каре
    for i in range(3, len(Tab_and_p)):
        if ((Tab_and_p[i].val == Tab_and_p[i-1].val and Tab_and_p[i].val == Tab_and_p[i-2].val and Tab_and_p[i].val == Tab_and_p[i-3].val) and (Tab_and_p[i] != 't' or Tab_and_p[i-1] != 't' or Tab_and_p[i-2] != 't' or Tab_and_p[i-3] != 't')):
            if (Player_cards == Player1_cards):
                results['p1'] = Combination['Four of a Kind']
                results['p1 points'] = Tab_and_p[i].points + Tab_and_p[i - 1].points + Tab_and_p[i-2].points + Tab_and_p[i - 3].points
            elif (Player_cards == Player2_cards):
                results['p2'] = Combination['Four of a Kind']
                results['p2 points'] = Tab_and_p[i].points + Tab_and_p[i - 1].points + Tab_and_p[i-2].points + Tab_and_p[i - 3].points
            print('Каре')

#Алгоритм поиска Стрит-Флэша
    for i in range(4, len(Tab_and_p)):
        if ((Tab_and_p[i].points == Tab_and_p[i-1].points - 1 and Tab_and_p[i].points == Tab_and_p[i-2].points - 2 and Tab_and_p[i].points == Tab_and_p[i-3].points - 3 and Tab_and_p[i].points == Tab_and_p[i-4].points - 4) and (Tab_and_p[i].suit == Tab_and_p[i-1].suit and Tab_and_p[i].suit == Tab_and_p[i-2].suit and Tab_and_p[i].suit == Tab_and_p[i-3].suit and Tab_and_p[i].suit == Tab_and_p[i-4].suit)):
            if (Player_cards == Player1_cards):
                results['p1'] = Combination['Straight-flush']
                results['p1 points'] = Tab_and_p[i].points + Tab_and_p[i-1].points + Tab_and_p[i-2].points + Tab_and_p[i-3].points + Tab_and_p[i-4].points
            elif (Player_cards == Player2_cards):
                results['p2'] = Combination['Straight-flush']
                results['p2 points'] = Tab_and_p[i].points + Tab_and_p[i-1].points + Tab_and_p[i-2].points + Tab_and_p[i-3].points + Tab_and_p[i-4].points
            print('Стрит-Флэш')

#Алгоритм поиска Флэш-Рояля
    for i in range(4, len(Tab_and_p)):
        if (Tab_and_p[i].val == 'Ace' and (Tab_and_p[i].points == Tab_and_p[i-1].points - 1 and Tab_and_p[i].points == Tab_and_p[i-2].points - 2 and Tab_and_p[i].points == Tab_and_p[i-3].points - 3 and Tab_and_p[i].points == Tab_and_p[i-4].points - 4) and (Tab_and_p[i].suit == Tab_and_p[i-1].suit and Tab_and_p[i].suit == Tab_and_p[i-2].suit and Tab_and_p[i].suit == Tab_and_p[i-3].suit and Tab_and_p[i].suit == Tab_and_p[i-4].suit)):
            if (Player_cards == Player1_cards):
                results['p1'] = Combination['Straight-flush']
                results['p1 points'] = Tab_and_p[i].points + Tab_and_p[i-1].points + Tab_and_p[i-2].points + Tab_and_p[i-3].points + Tab_and_p[i-4].points
            elif (Player_cards == Player2_cards):
                results['p2'] = Combination['Straight-flush']
                results['p2 points'] = Tab_and_p[i].points + Tab_and_p[i-1].points + Tab_and_p[i-2].points + Tab_and_p[i-3].points + Tab_and_p[i-4].points
            print('Флэш-Рояль')

def end_game():

    bckgrnd = pygame.image.load('end_game_background.png')

    global results
    check(Player1_cards, Table_cards)
    check(Player2_cards, Table_cards)

    restart_btn = Button(280, 70)
    back_to_menu_btn = Button(290, 70)

    end = True
    while end:

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        display.blit(bckgrnd, (0, 0))
        restart_btn.draw(display_width / 2 - 150, display_height / 2 - 65, 'Играть заново', settings, (0, 0, 0), 40, 10, 15)
        back_to_menu_btn.draw(display_width / 2 - 155, display_height / 2 + 50, 'Выйти из игры', show_menu, (0, 0, 0), 40, 10, 15)

        output_text('КОНЕЦ ИГРЫ', display_width / 2 - 200, display_height / 2 - 210, (0, 0, 0), font_size = 60)

        if results['p1'] == results['p2']:
            if results['p1 points'] == results['p2 points']:
                output_text('Ничья', display_width / 2 - 100, display_height / 2 - 130, (0, 0, 0))
            elif results['p1 points'] > results['p2 points']:
                output_text('Первый игрок выиграл', display_width / 2 - 150, display_height / 2 - 130, (0, 0, 0))
            elif results['p1 points'] < results['p2 points']:
                output_text('Второй игрок выиграл', display_width / 2 - 150, display_height / 2 - 130, (0, 0, 0))
        elif results['p1'] > results['p2']:
            output_text('Первый игрок выиграл', display_width/2 - 150, display_height/2 - 130, (0, 0, 0))
        elif results['p1'] < results['p2']:
            output_text('Второй игрок выиграл', display_width/2 - 150, display_height/2 - 130, (0, 0, 0))

        pygame.display.update()

def output_text(message, x, y, font_color, font_type = 'times-new-roman.ttf', font_size = 30):
    font_type = pygame.font.Font(font_type, font_size)
    text = font_type.render(message, True, font_color)
    display.blit(text, (x, y))

show_menu()

pygame.quit()
quit()


from flask import Flask, request,jsonify
import json
import sqlite3

app = Flask(__name__)
app.config['DEBUG'] = True

#Do NOT put functions/statement outside functions

# Show your student ID
@app.route('/mystudentID/', methods=['GET'])
def my_student_id():
    response={"studentID": "12345678G"}
    return jsonify(response), 200, {'Content-Type': 'application/json'}

if __name__ == '__main__':
   app.run()


import cv2

contours, hierarchy = cv.findContours(img_binary, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)

# iterate contour and draw
for cnt in contours:
  cv2.drawContours(img, contours, -1, (0,0,255), 1)

# calculate contour area
area = cv.contourArea(cnt)

# approximate contour
epsilon = 0.02 * cv.arcLength(cnt, True)
approx = cv.approxPolyDP(cnt, epsilon, True)

# calculate contour center
for cnt in contours:
    M = cv.moments(cnt)
    cx = int(M['m10']/M['m00'])
    cy = int(M['m01']/M['m00'])
    cv.circle(img_color, (cx, cy), 10, (0,0,255), -1)

# Get bounding rectangle
x, y, w, h = cv.boundingRect(cnt)

# Get rotated rectangle
rect = cv.minAreaRect(cnt)
box = cv.boxPoints(rect)
box = np.int0(box)

# get convex hull shape
hull = cv.convexHull(cnt)

# Convexity defects
hull = cv.convexHull(cnt, returnPoints = False)
defects = cv.convexityDefects(cnt, hull)

# minimum enclosing circle
(x,y), radius = cv2.minEnclosingCircle(cnt)
center=(int(x), int(y))
radius=int(radius)

# fitting an ellipse
ellipse = cv2.fitEllipse(cnt)
img=cv2.ellipse(img, ellipse, (0,255,0),2)

# fitting a line
[vx,vy,x,y] = cv2.fitLine(max_contour,cv2.DIST_L2,0,0.01,0.01)
lefty = int((-x*vy/vx) + y)
righty = int(((img_gray.shape[1]-x)*vy/vx)+y)
PT1 = (0,lefty)
PT2 = (img_gray.shape[1]-1,righty)


from typing import List, Tuple, Union, Generator
from loguru import logger
import requests
import json
from .base import LLM

class ErnieBot(LLM):
    def __init__(self, api_key, model_name="ernie-bot-turbo") -> None:
        super().__init__()
        self.llm_type = 'erniebot'
        # curl 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=【API Key】&client_secret=【Secret Key】'
        self.api_key = api_key  # api_key is actually access_token get from above curl command
        self.model_name = model_name
        self.api = f"https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant?access_token={self.api_key}"

    def ask_stream(self, query: str, history: List[Tuple[str]] = [], incremental: bool = False,
                   temperature: float = 0.5, top_p: float = 0.7, presence_penalty: float = 0,
                   frequency_penalty: float = 0, timeout: Tuple[float] | float = (15, 30), **kwargs) -> Generator:
        logger.info(f"erniebot api parameters: temperature={temperature}, top_p={top_p}, presence_penalty={presence_penalty}, frequency_penalty={frequency_penalty}")
        history = [{'user': q, 'bot': a} for q, a in history]
        logger.info(f"erniebot history: {history}, query={query}")
        messages = []
        for q, a in history:
            messages.append({"role": "user", "content": q})
            messages.append({"role": "assistant", "content": a})
        messages.append({"role": "user", "content": query})
        data = {"messages": messages, "stream": True}
        logger.info(f"erniebot final prompt: {data}")
        response = requests.post(self.api, json=data, stream=True, timeout=timeout)
        all_content = ""
        data = b""
        for chunk in response:
            for line in chunk.splitlines(True):
                data += line
                if data.endswith((b"\r\r", b"\n\n", b"\r\n\r\n")):
                    line_str = data.decode()
                    json_str = line_str[6:]
                    json_data = json.loads(json_str)
                    text = json_data["result"]
                    if incremental:
                        yield text
                    else:
                        all_content += text
                        yield all_content
                    data = b""
        if data:
            line_str = data.decode()
            json_str = line_str[6:]
            json_data = json.loads(json_str)
            text = json_data["result"]
            if incremental:
                yield text
            else:
                all_content += text
                yield all_content

    def ask(self, query: str, history: List[Tuple[str]] = [],
            temperature: float = 0.5, top_p: float = 0.7, presence_penalty: float = 0,
            frequency_penalty: float = 0, timeout: Tuple[float] | float = (15, 30), **kwargs) -> str:
        logger.info(f"erniebot api parameters: temperature={temperature}, top_p={top_p}, presence_penalty={presence_penalty}, frequency_penalty={frequency_penalty}")
        history = [{'user': q, 'bot': a} for q, a in history]
        logger.info(f"erniebot history: {history}, query={query}")
        messages = []
        for q, a in history:
            messages.append({"role": "user", "content": q})
            messages.append({"role": "assistant", "content": a})
        messages.append({"role": "user", "content": query})
        data = {"messages": messages, "stream": False}
        logger.info(f"erniebot final prompt: {data}")
        response = requests.post(self.api, json=data, timeout=timeout)
        json_data = response.json()
        text = json_data["result"]
        return text

    @classmethod
    def config_info(cls) -> str:
        info = """
        erniebot config info:
        api_key: None (required)
        model_name: ernie-bot-turbo
        """
        return info

    @classmethod
    def check_config(cls, **kwargs)->bool:
        if kwargs.get("api_key", None) is None:
            return False
        return True


import gatetools as gt
import itk
import click
import numpy as np
import sys

# -----------------------------------------------------------------------------
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
@click.command(context_settings=CONTEXT_SETTINGS)

@click.option('--input', '-i', help='Input image filename', required=True,
                type=click.Path(dir_okay=False))
@click.option('--axis', '-p', help='Axis of the projection', default=0)
@click.option('--mean', '-m', help='Compute the mean of the projected image', is_flag=True)
@click.option('--output', '-o', help='Output filename', required=True,
                type=click.Path(dir_okay=False,
                              writable=True, readable=False,
                              resolve_path=True, allow_dash=False, path_type=None))

def image_projection_click(input, axis, mean, output):
    '''
    Project the input along the axis. Compute the mean of the projection along this axis if the flag is set
    '''

    inputImage = itk.imread(input)
    outputImage = image_projection(inputImage, axis, mean)
    itk.imwrite(outputImage, output)

# -----------------------------------------------------------------------------
def image_projection(image, axis=0, mean=False):

    array = (itk.array_from_image(image)).astype(float)
    if image.GetImageDimension() == 3:
        array = np.swapaxes(array, 0, 2)
    projectedArray = np.sum(array, axis)

    if mean:
        projectedArray = projectedArray / image.GetLargestPossibleRegion().GetSize()[axis]

    outputImage = itk.image_from_array(projectedArray)
    spacing =  np.array(image.GetSpacing())
    spacing = np.delete(spacing, axis)
    outputImage.SetSpacing(spacing)
    origin =  np.array(image.GetOrigin())
    origin = np.delete(origin, axis)
    outputImage.SetOrigin(origin)
    return outputImage

# -----------------------------------------------------------------------------
if __name__ == '__main__':
    image_projection_click()

# -----------------------------------------------------------------------------
import unittest
import os

def createImageExample():
    x = np.arange(0, 23, 1)
    y = np.arange(20, 41, 1)
    z = np.arange(10, 25, 1)
    xx, yy, zz = np.meshgrid(x, y, z)
    image = itk.image_from_array(np.int16(xx))
    image.SetSpacing([1.1, 2, 3.1])
    image.SetOrigin([10, 12.4, -0.7])
    return image

class Test_Image_Projection(unittest.TestCase):
    def test_image_projection(self):
        image = createImageExample()
        output=image_projection(image, 0, False)
        outputArray = itk.array_view_from_image(output)
        self.assertTrue(outputArray[13, 14] == 14*15)
        self.assertTrue(output.GetSpacing()[0] == 2)
        self.assertTrue(output.GetSpacing()[1] == 3.1)
        self.assertTrue(output.GetOrigin()[0] == 12.4)
        self.assertTrue(output.GetOrigin()[1] == -0.7)
        self.assertTrue(output.GetLargestPossibleRegion().GetSize()[0] == 23)
        self.assertTrue(output.GetLargestPossibleRegion().GetSize()[1] == 21)
        output=image_projection(image, 1, False)
        outputArray = itk.array_view_from_image(output)
        self.assertTrue(outputArray[8, 5] == 253)
        self.assertTrue(output.GetSpacing()[0] == 1.1)
        self.assertTrue(output.GetSpacing()[1] == 3.1)
        self.assertTrue(output.GetOrigin()[0] == 10)
        self.assertTrue(output.GetOrigin()[1] == -0.7)
        self.assertTrue(output.GetLargestPossibleRegion().GetSize()[0] == 15)
        self.assertTrue(output.GetLargestPossibleRegion().GetSize()[1] == 21)
        output=image_projection(image, 2)
        outputArray = itk.array_view_from_image(output)
        self.assertTrue(outputArray[6, 10] == 6*21)
        self.assertTrue(output.GetSpacing()[0] == 1.1)
        self.assertTrue(output.GetSpacing()[1] == 2)
        self.assertTrue(output.GetOrigin()[0] == 10)
        self.assertTrue(output.GetOrigin()[1] == 12.4)
        self.assertTrue(output.GetLargestPossibleRegion().GetSize()[0] == 15)
        self.assertTrue(output.GetLargestPossibleRegion().GetSize()[1] == 23)
        output=image_projection(image, 2, True)
        outputArray = itk.array_view_from_image(output)
        self.assertTrue(outputArray[6, 10] == 6)


from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, DateTime
from datetime import datetime

Base = declarative_base()

class Subject(Base):
    __tablename__ = 'Subjects'
    id = Column(Integer, primary_key=True)
    name = Column(String(50), unique=True)
    quantity = Column(Integer)

class Customer(Base):
    __tablename__ = "Customers"
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String(32), nullable=False)
    address = Column(String(32), nullable=False)
    passport_details = Column(String(32), nullable=False, unique=True)
    phone_number = Column(String(32), nullable=False)

class Order(Base):
    __tablename__ = "Orders"
    id = Column(Integer, primary_key=True, index=True)
    customer_id = Column(Integer, nullable=False)
    subject_name = Column(String(50), nullable=False)
    quantity = Column(Integer, nullable=False)
    created_at = Column(DateTime, default=datetime.utcnow)

class Audit(Base):
    __tablename__ = "Audit"
    id = Column(Integer, primary_key=True, index=True)
    username = Column(String(64), nullable=False)
    action = Column(String(64), nullable=False)
    created_at = Column(DateTime, default=datetime.utcnow)


from vae.train import VAE, trainVAE

import scipy.sparse
from pathlib import Path

if __name__ == "__main__":
    latent_dimension = 10
    batch_size = 100

    embeddings_directory = Path("embeddings")
    embeddings_directory.mkdir(parents=True, exist_ok=True)
    data = scipy.sparse.load_npz("raw_gene_expression.npz").toarray()
    trainVAE(data, str(embeddings_directory), "pbmc")

    model = VAE(input_dim=data.shape[1], latent_dim=latent_dimension)
    model.load_state_dict(torch.load("embeddings/pbmc.pt")["model_state_dict"])

    results = np.zeros((data.shape[0], latent_dimension))
    for batch in range(len(data) // batch_size + 1):
       batch_data = data[batch * batch_size : (batch+1) * batch_size].astype(np.float32)
       padded_batch_data = np.zeros((batch_size, data.shape[1])).astype(np.float32)
       padded_batch_data[:len(batch_data)] = batch_data
       _, latent_z, *_ = model.forward(padded_batch_data)
       results[batch * batch_size : (batch+1) * batch_size] = latent_z.detach()[:len(batch_data)]
       print(batch)
    np.save(embeddings_directory / "scvis_embeddings.npy", results)


from pyrogram import Client, filters, enums
from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup
from pyrogram.errors.exceptions.bad_request_400 import MessageTooLong, PeerIdInvalid
from info import ADMINS, LOG_CHANNEL, SUPPORT_CHAT, MELCOW_NEW_USERS
from database.users_chats_db import db
from database.ia_filterdb import Media
from utils import get_size, temp, get_settings
from Script import script
from pyrogram.errors import ChatAdminRequired

"""-----------------------------------------https://t.me/GetTGLink/4179 --------------------------------------"""

@Client.on_message(filters.new_chat_members & filters.group)
async def save_group(bot, message):
    r_j_check = [u.id for u in message.new_chat_members]
    if temp.ME in r_j_check:
        if not await db.get_chat(message.chat.id):
            total=await bot.get_chat_members_count(message.chat.id)
            r_j = message.from_user.mention if message.from_user else "Anonymous"
            await bot.send_message(LOG_CHANNEL, script.LOG_TEXT_G.format(message.chat.title, message.chat.id, total, r_j))
            await db.add_chat(message.chat.id, message.chat.title)
        if message.chat.id in temp.BANNED_CHATS:
            # Inspired from a boat of a banana tree
            buttons = [[
                InlineKeyboardButton('sᴜᴘᴘᴏʀᴛ', url=f'https://t.me/{SUPPORT_CHAT}')
            ]]
            reply_markup=InlineKeyboardMarkup(buttons)
            k = await message.reply(
                text='ᴄʜᴀᴛ ɴᴏᴛ ᴀʟʟᴏᴡᴇᴅ 🐞\n\nMʏ ᴀᴅᴍɪɴꜱ ʜᴀꜱ ʀᴇꜱᴛʀɪᴄᴛᴇᴅ ᴍᴇ ғʀᴏᴍ ᴡᴏʀᴋɪɴɢ ʜᴇʀᴇ ! Iғ ʏᴏᴜ ᴡᴀɴᴛ ᴛᴏ ᴋɴᴏᴡ ᴍᴏʀᴇ ᴀʙᴏᴜᴛ ɪᴛ ᴄᴏɴᴛᴀᴄᴛ ꜱᴜᴘᴘᴏʀᴛ..',
                reply_markup=reply_markup,
            )

            try:
                await k.pin()
            except:
                pass
            await bot.leave_chat(message.chat.id)
            return
        buttons = [[
            InlineKeyboardButton('ℹ Hᴇʟᴘ ℹ', url=f"https://t.me/{temp.U_NAME}?start=help"),
            InlineKeyboardButton('📢 ᴜᴘᴅᴀᴛᴇs 📢', url='https://t.me/TamilanBotsZ')
        ]]
        reply_markup=InlineKeyboardMarkup(buttons)
        await message.reply_text(
            text=f"ᴛʜᴀɴᴋs ғᴏʀ ᴀᴅᴅɪɴɢ ᴍᴇ ɪɴ {message.chat.title} ❣\n\nɪғ ᴜ ᴀsᴋ ǫᴜᴇsᴛɪᴏɴs & ᴅᴏᴜʙᴛs ɪɴ sᴜᴘᴘᴏʀᴛ",
            reply_markup=reply_markup)
    else:
        settings = await get_settings(message.chat.id)
        if settings["welcome"]:
            for u in message.new_chat_members:
                if (temp.MELCOW).get('welcome') is not None:
                    try:
                        await (temp.MELCOW['welcome']).delete()
                    except:
                        pass
                temp.MELCOW['welcome'] = await message.reply(f"Hey , {u.mention}, Welcome to {message.chat.title}")

@Client.on_message(filters.command('leave') & filters.user(ADMINS))
async def leave_a_chat(bot, message):
    if len(message.command) == 1:
        return await message.reply('ɢɪᴠᴇ ᴍᴇ ᴄʜᴀᴛ ɪᴅ')
    chat = message.command[1]
    try:
        chat = int(chat)
    except:
        chat = chat
    try:
        buttons = [[
            InlineKeyboardButton('sᴜᴘᴘᴏʀᴛ', url=f'https://t.me/{SUPPORT_CHAT}')
        ]]
        reply_markup=InlineKeyboardMarkup(buttons)
        await bot.send_message(
            chat_id=chat,
            text='Hello Friends, \nMy admin has told me to leave from group so i go! If you wanna add me again contact my support group.',
            reply_markup=reply_markup,
        )

        await bot.leave_chat(chat)
        await message.reply(f"left the chat `{chat}`")
    except Exception as e:
        await message.reply(f'Error - {e}')

@Client.on_message(filters.command('disable') & filters.user(ADMINS))
async def disable_chat(bot, message):
    if len(message.command) == 1:
        return await message.reply('ɢɪᴠᴇ ᴍᴇ ᴀ ᴄʜᴀᴛ ɪᴅ')
    r = message.text.split(None)
    if len(r) > 2:
        reason = message.text.split(None, 2)[2]
        chat = message.text.split(None, 2)[1]
    else:
        chat = message.command[1]
        reason = "No reason Provided"
    try:
        chat_ = int(chat)
    except:
        return await message.reply('ɢɪᴠᴇ ᴍᴇ ᴀ ᴠᴀʟɪᴅ ᴄʜᴀᴛ ɪᴅ')
    cha_t = await db.get_chat(int(chat_))
    if not cha_t:
        return await message.reply("ᴄʜᴀᴛ ɴᴏᴛ ғᴏᴜɴᴅ ɪɴ ᴍʏ ᴅʙ")
    if cha_t['is_disabled']:
        return await message.reply(f"ᴛʜɪs ᴄʜᴀᴛ ɪs ᴀʟʀᴇᴀᴅʏ ᴅɪsᴀʙʟᴇᴅ:\nReason- {cha_t['reason']} ")
    await db.disable_chat(int(chat_), reason)
    temp.BANNED_CHATS.append(int(chat_))
    await message.reply('ᴄʜᴀᴛ sᴜᴄᴄᴇssғᴜʟʟʏ ᴅɪsᴀʙʟᴇᴅ')
    try:
        buttons = [[
            InlineKeyboardButton('sᴜᴘᴘᴏʀᴛ', url=f'https://t.me/{SUPPORT_CHAT}')
        ]]
        reply_markup=InlineKeyboardMarkup(buttons)
        await bot.send_message(
            chat_id=chat_,
            text=f'ʜᴇʟʟᴏ ғʀɪᴇɴᴅ, \nMʏ ᴀᴅᴍɪɴ ʜᴀꜱ ᴛᴏʟᴅ ᴍᴇ ᴛᴏ ʟᴇᴀᴠᴇ ғʀᴏᴍ ɢʀᴏᴜᴘ ꜱᴏ ɪ ɢᴏ! Iғ ʏᴏᴜ ᴡᴀɴɴᴀ ᴀᴅᴅ ᴍᴇ ᴀɢᴀɪɴ ᴄᴏɴᴛᴀᴄᴛ ᴍʏ ꜱᴜᴘᴘᴏʀᴛ ɢʀᴏᴜᴘ. \nReason : {reason}',
            reply_markup=reply_markup)
        await bot.leave_chat(chat_)
    except Exception as e:
        await message.reply(f"Error - {e}")

@Client.on_message(filters.command('enable') & filters.user(ADMINS))
async def re_enable_chat(bot, message):
    if len(message.command) == 1:
        return await message.reply('ɢɪᴠᴇ ᴍᴇ ᴀ ᴄʜᴀᴛ ɪᴅ')
    chat = message.command[1]
    try:
        chat_ = int(chat)
    except:
        return await message.reply('ɢɪʙᴇ ᴍᴇ ᴀ ᴠᴀʟɪᴅ ᴄʜᴀᴛ ɪᴅ')
    sts = await db.get_chat(int(chat))
    if not sts:
        return await message.reply("ᴄʜᴀᴛ ɴᴏᴛ ғᴏᴜɴᴅ ɪɴ ᴍʏ ᴅʙ !")
    if not sts.get('is_disabled'):
        return await message.reply('ᴛʜɪs ᴄʜᴀᴛ ɪs ɴᴏᴛ ʏᴇᴛ ᴅɪsᴀʙʟᴇᴅ.')
    await db.re_enable_chat(int(chat_))
    temp.BANNED_CHATS.remove(int(chat_))
    await message.reply("ᴄʜᴀᴛ sᴜᴄᴄᴇssғᴜʟʟʏ ʀᴇ-ᴇɴᴀʙʟᴇᴅ")

@Client.on_message(filters.command('stats') & filters.incoming)
async def get_ststs(bot, message):
    rju = await message.reply('ғᴇᴛᴄʜɪɴɢ sᴛᴀᴛs..')
    total_users = await db.total_users_count()
    totl_chats = await db.total_chat_count()
    files = await Media.count_documents()
    size = await db.get_db_size()
    free = 536870912 - size
    size = get_size(size)
    free = get_size(free)
    await rju.edit(script.STATUS_TXT.format(files, total_users, totl_chats, size, free))

# a function for trespassing into others groups, Inspired by a Vazha
# Not to be used , But Just to showcase his vazhatharam.
# @Client.on_message(filters.command('invite') & filters.user(ADMINS))
async def gen_invite(bot, message):
    if len(message.command) == 1:
        return await message.reply('ɢɪᴠᴇ ᴍᴇ ᴀ ᴄʜᴀᴛ ɪᴅ')
    chat = message.command[1]
    try:
        chat = int(chat)
    except:
        return await message.reply('ɢɪᴠᴇ ᴍᴇ ᴀ ᴠᴀʟɪᴅ ᴄʜᴀᴛ ɪᴅ')
    try:
        link = await bot.create_chat_invite_link(chat)
    except ChatAdminRequired:
        return await message.reply("Iɴᴠɪᴛᴇ Lɪɴᴋ Gᴇɴᴇʀᴀᴛɪᴏɴ Fᴀɪʟᴇᴅ, Iᴀᴍ Nᴏᴛ Hᴀᴠɪɴɢ Sᴜғғɪᴄɪᴇɴᴛ Rɪɢʜᴛꜱ")
    except Exception as e:
        return await message.reply(f'Error {e}')
    await message.reply(f'ʜᴇʀᴇ ᴜʀ ɪɴᴠɪᴛᴇ ʟɪɴᴋ {link.invite_link}')

@Client.on_message(filters.command('ban') & filters.user(ADMINS))
async def ban_a_user(bot, message):
    # https://t.me/GetTGLink/4185
    if len(message.command) == 1:
        return await message.reply('ɢɪᴠᴇ ᴍᴇ ᴀ ɪᴅ/ᴜsᴇʀɴᴀᴍᴇ')
    r = message.text.split(None)
    if len(r) > 2:
        reason = message.text.split(None, 2)[2]
        chat = message.text.split(None, 2)[1]
    else:
        chat = message.command[1]
        reason = "No reason Provided"
    try:
        chat = int(chat)
    except:
        pass
    try:
        k = await bot.get_users(chat)
    except PeerIdInvalid:
        return await message.reply("Tʜɪꜱ ɪꜱ ᴀɴ ɪɴᴠᴀʟɪᴅ ᴜꜱᴇʀ, ᴍᴀᴋᴇ ꜱᴜʀᴇ ɪᴀ ʜᴀᴠᴇ ᴍᴇᴛ ʜɪᴍ ʙᴇғᴏʀᴇ.")
    except IndexError:
        return await message.reply("Tʜɪꜱ ᴍɪɢʜᴛ ʙᴇ ᴀ ᴄʜᴀɴɴᴇʟ, ᴍᴀᴋᴇ ꜱᴜʀᴇ ɪᴛꜱ ᴀ ᴜꜱᴇʀ.")
    except Exception as e:
        return await message.reply(f'Error - {e}')
    else:
        jar = await db.get_ban_status(k.id)
        if jar['is_banned']:
            return await message.reply(f"{k.mention} ɪs ᴀʟʀᴇᴀᴅʏ ʙᴀɴɴᴇᴅ \nReason: {jar['ban_reason']}")
        await db.ban_user(k.id, reason)
        temp.BANNED_USERS.append(k.id)
        await message.reply(f"sᴜᴄᴄᴇssғᴜʟʟʏ ʙᴀɴɴᴇᴅ {k.mention}")

@Client.on_message(filters.command('unban') & filters.user(ADMINS))
async def unban_a_user(bot, message):
    if len(message.command) == 1:
        return await message.reply('ɢɪᴠᴇ ᴍᴇ ᴀ ᴜsᴇʀ ɪᴅ/ᴜsᴇʀɴᴀᴍᴇ')
    r = message.text.split(None)
    if len(r) > 2:
        reason = message.text.split(None, 2)[2]
        chat = message.text.split(None, 2)[1]
    else:
        chat = message.command[1]
        reason = "No reason Provided"
    try:
        chat = int(chat)
    except:
        pass
    try:
        k = await bot.get_users(chat)
    except PeerIdInvalid:
        return await message.reply("Tʜɪꜱ ɪꜱ ᴀɴ ɪɴᴠᴀʟɪᴅ ᴜꜱᴇʀ, ᴍᴀᴋᴇ ꜱᴜʀᴇ ɪᴀ ʜᴀᴠᴇ ᴍᴇᴛ ʜɪᴍ ʙᴇғᴏʀᴇ.,")
    except IndexError:
        return await message.reply("Tʜɪꜱ ᴍɪɢʜᴛ ʙᴇ ᴀ ᴄʜᴀɴɴᴇʟ, ᴍᴀᴋᴇ ꜱᴜʀᴇ ɪᴛꜱ ᴀ ᴜꜱᴇʀ..")
    except Exception as e:
        return await message.reply(f'Error - {e}')
    else:
        jar = await db.get_ban_status(k.id)
        if not jar['is_banned']:
            return await message.reply(f"{k.mention} ɪs ɴᴏᴛ ʏᴇᴅ ʙᴀɴɴᴇᴅ ")
        await db.remove_ban(k.id)
        temp.BANNED_USERS.remove(k.id)
        await message.reply(f"sᴜᴄᴄᴇsғᴜʟʟʏ ʙᴀɴɴᴇᴅ {k.mention}")

@Client.on_message(filters.command('users') & filters.user(ADMINS))
async def list_users(bot, message):
    # https://t.me/GetTGLink/4184
    raju = await message.reply('ɢᴇᴛᴛɪɴɢ ʟɪsᴛs ᴏғ ᴜsᴇʀs')
    users = await db.get_all_users()
    out = "ᴜsᴇʀs sᴀᴠᴇᴅ ɪɴ ᴍʏ ᴅʙ:\n\n"
    async for user in users:
        out += f"{user['name']}"
        if user['ban_status']['is_banned']:
            out += '( Banned User )'
        out += '\n'
    try:
        await raju.edit_text(out)
    except MessageTooLong:
        with open('users.txt', 'w+') as outfile:
            outfile.write(out)
        await message.reply_document('users.txt', caption="List Of Users")

@Client.on_message(filters.command('chats') & filters.user(ADMINS))
async def list_chats(bot, message):
    raju = await message.reply('ɢᴇᴛᴛɪɴɢ ʟɪsᴛs ᴏғ ᴜsʀʀs')
    chats = await db.get_all_chats()
    out = "ᴄʜᴀᴛs sᴀᴠᴇᴅ ɪɴ ᴍʏ ᴅʙ:\n\n"
    async for chat in chats:
        out += f"**Title:** `{chat['title']}`\n**- ID:** `{chat['id']}`"
        if chat['chat_status']['is_disabled']:
            out += '( Disabled Chat )'
        out += '\n'
    try:
        await raju.edit_text(out)
    except MessageTooLong:
        with open('chats.txt', 'w+') as outfile:
            outfile.write(out)
        await message.reply_document('chats.txt', caption="List Of Chats")


'''
-----------------------------------------------------------------------
                      Additional Documentation

Made by Zachary A Brader, Kieran Coito, Pedro Goncalves Mokarzel
while attending University of Washington Bothell
Made in 03/09/2020
Based on instruction in CSS 458,
taught by professor Johnny Lin
Notes:
- Written for Python 3.7.3.
- No executable
- Modules necessary: pygame, datetime
- External necessities: variables.py
- Makes animation of model

=======================================================================
'''

# =======================================================================
# ============================= Imports =================================
# =======================================================================

import pygame
from pygame import display
import variables as v
from datetime import timedelta

# =======================================================================
# ================================= Class ===============================
# =======================================================================

# Class to preform animation logic via pygame
class visual():
    # Initialize pygame module
    pygame.init()

    # Screen size in pixels
    displayWidth = 450
    displayHeight = 450

    # Create Screen / Display Window
    screen = display.set_mode((displayWidth, displayHeight))

    # Create clock to control frame rate
    clock = pygame.time.Clock()

    # Provide a caption for the window
    display.set_caption("CSS 458 Group - Pedro Is a Meme")

    # List of colors to pull from as needed
    black = (0, 0, 0)
    white = (255, 255, 255)
    red = (255, 0, 0)
    green = (0, 200, 0)
    bright_red = (255, 0, 0)
    bright_green = (0, 255, 0)
    blue = (0, 0, 255)

    # Fonts to choose from
    font = pygame.font.Font(None, 32)
    smallFont = pygame.font.Font(None, 20)  # Used inside text boxes

    # Ignore
    def __init__(self):
        pass

    def print_env(self, modelObj, update_time=1, start_time=None):
        """ Visualizes a set of data stored inside a model object for the time
            specified in update_time.

            Preconditions:
            - modelObj: The current state of the model to visualize.
            - update_time: The time to display the visualization for.
                This number is in milliseconds, so 1000 ms = 1 second.

            Postcondition:
            - Prints an environment that shows both the cashiers and customers,
                and allows the user to determine statistics about the cashier or customer
                by hovering over them with the mouse.
        """

        # Pulls environment
        line = modelObj.line
        # Reference to cashiers
        cashiers = line.cashier_list

        # List of item's remaining
        item_list = modelObj.list_of_items_checked

        # Customers waiting to get into line
        cust_waiting = modelObj.list_of_customers_in_line

        # Model is updated by this many seconds each iteration
        cur_time_step = (60 / v.TIME_STEP) * len(item_list)

        start_hour = None
        if start_time is not None:
            start_hour = timedelta(seconds=(start_time * 3600))

        # Tells the loop to keep displaying until a certain condition is met
        active = True

        # Record when we this visualization
        startTimer = pygame.time.get_ticks()

        # Main logic
        while active:
            # Check for user interaction
            for event in pygame.event.get():
                # If the user exits out of the animation window
                if event.type == pygame.QUIT:
                    # Return false so the model doesn't keep making
                    # the window reappear
                    return False

            # Has this model been going for longer than the time in update_time?
            if (pygame.time.get_ticks() - startTimer) > (update_time * 1000):
                # The user didn't intervene, tell model
                # to keep showing the animation
                return True

            # Set background
            self.screen.fill(self.black)

            # Print Statistics about current timestep inside

            if start_time is None:
                # a text box at the top of the screen
                self.text_box(str(cur_time_step) + " Seconds",
                              int(self.displayWidth / 4), 0, width=int(self.displayWidth / 2), height=25)
            else:
                self.text_box(str(start_hour + timedelta(seconds=cur_time_step))[:-3],
                              int(self.displayWidth / 4), 0, width=int(self.displayWidth / 2), height=25)

            # Print the customers waiting to go into line
            self.text_box("Customers Not in Line: " + str(int(cust_waiting[-1])),
                          int(self.displayWidth / 4), 30, width=int(self.displayWidth / 2), height=25)

            # Print cashiers
            self.print_floor(cashiers)

            # Update screen
            pygame.display.flip()
            self.clock.tick(30)

    def print_floor(self, cashiers):
        """ Takes in the list of all the current cashiers and displays them on the screen

            Precondition:
            - cashiers: A list of all the cashiers from our model object

            Postcondition:
             - The animation will now display all the cashiers correctly
        """
        # Store the total number of cashiers for readability
        num_cashiers = len(cashiers)

        # Determine how much room we need to divide the screen equally
        dist = int(self.displayWidth / min((num_cashiers + 1), 6))

        # Print up to three rows
        for row in range(max(int(num_cashiers / 6 + 1), 1)):
            # Print up to five cashiers
            for column in range(min(num_cashiers - (5 * row), 5)):
                # To make the data readable, we will only show the first 20 cashiers.
                if row * 5 + column < 19:
                    # Print a cashier and it's customers
                    self.print_both(cashiers[column + row * 5], cashiers[column + row * 5].cashier_queue, column, row, dist)
                # Print the rest of the cashiers inside a single box with a number representing them
                else:
                    # Show the rest of the cashiers as a single text box
                    self.print_final_cashier(dist * (column + 1),
                                             self.displayHeight / 3 + (80 * row),
                                             sum([1 for x in range(15, len(cashiers)) if not cashiers[x].self_checkout]),
                                             sum([1 for x in range(15, len(cashiers)) if cashiers[x].self_checkout]),
                                             sum([len(cashiers[x].cashier_queue) for x in range(15, len(cashiers))]))
                    # We don't need to print any other cashiers
                    return

    def print_both(self, cashier, queue, cashier_num, row, dist):
        """ Print a single cashier and their customers

            Postcondition:
            - cashier: A cashier object
            - queue: The list of customers attached to a cashier object
            - cashier_num: This correlates to the column number of the cashier; It is
                used to find the the x value
            - row: Which row the cashier is on; This is used to find the y value
            - dist: The distance between each cashier on the x-axis

            Postcondition:
            - A cashier is visualized on the screen with their current line. As well,
                the user can interact with them by hovering over them
        """

        # Where to print the cashier on the x axis
        xPos = dist * (cashier_num + 1)

        # The initial height of the cashier on the screen
        height = self.displayHeight / 3

        # Print the cashier object
        self.print_cashier(xPos, height + (80 * row), cashier)

        # Print the cashier's line
        self.print_line(xPos, height + (80 * row), queue)

    def print_cashier(self, x, y, cashier):
        """ Print a single cashier object

            Precondition:
            - x: The x coordinate of the cashier on the screen
            - y: The y coordinate of the cashier on the screen
            - cashier: The cashier object to print

            Postcondition:
            - Prints a visual box to represent a cashier. Upon hovering
                over it, statistics about that specific cashier will appear
        """

        # Check the mouse's position
        mouse = pygame.mouse.get_pos()

        # Is the mouse over the box's position?
        if x + 25 > mouse[0] > x and y + 25 > mouse[1] > y:
            # Print a bright version of the cashier object
            if not cashier.self_checkout:
                # Print a highlighted regular cashier
                pygame.draw.rect(self.screen, self.bright_green, (x, y, 25, 25))
            else:
                # Print a highlighted self checkout
                pygame.draw.rect(self.screen, self.bright_red, (x, y, 25, 25))

            # Print statistics about the cashier at the top of the screen

            # Number of customers helped
            helpedText = "Helped: " + str(cashier.helped)
            self.text_box(helpedText, int(self.displayWidth / 6), 60, width=int(self.displayWidth / 6), height=25)

            # Cashiers Items Per Minute
            ipmText = "IPM: " + str(round(cashier.IPM, 2))
            self.text_box(ipmText, int(self.displayWidth / 3), 60, width=int(self.displayWidth / 6), height=25)

            # Total items checked out by this cashier
            itemText = "Items: " + str(round(cashier.total_items_checked, 2))
            self.text_box(itemText, int(self.displayWidth / 2), 60, width=int(self.displayWidth / 6), height=25)

            # Number of people in the cashier's line including the current person being helped
            custText = "Line: " + str(len(cashier.cashier_queue))
            self.text_box(custText, int(self.displayWidth * 2 / 3), 60, width=int(self.displayWidth / 6), height=25)

            # Cashier's chitchat levels
            chitText = "Chitchat: " + str(cashier.chatLevel)
            self.text_box(chitText, int(self.displayWidth / 3), 90, width=int(self.displayWidth / 6), height=25)

            # Empty box to make it look uniform
            self.text_box("", int(self.displayWidth / 2), 90, width=int(self.displayWidth / 6), height=25)
        # Mouse if not hovering over cashier
        else:
            # Print cashier object
            if not cashier.self_checkout:
                # Print normal cashier object
                pygame.draw.rect(self.screen, self.green, (x, y, 25, 25))
            else:
                # Print self checkout object
                pygame.draw.rect(self.screen, self.blue, (x, y, 25, 25))
        pass

    def print_final_cashier(self, x, y, num_cashiers, num_checkouts, num_custs):
        """ A final block to hold the unshown cashiers and self-checkouts

            Precondition:
            - x: The x-position of the block
            - y: The y-position of the block
            - num_cashiers: Total number of regular cashiers
            - num_checkouts: Total number of self-checkouts
            - num_custs: Total number of customers inside the cashiers' and
                self checkouts' lines

            Postcondition:
             Print a box at the specified coordinates that will tell the
                user about the number of cashiers, self checkouts, and customer's being
                helped when the user hovers over it.
        """

        # Get the mouse's position
        mouse = pygame.mouse.get_pos()

        # Is the mouse within the box's position
        if x + 25 > mouse[0] > x and y + 25 > mouse[1] > y:
            # Make a text box with the total number of cashiers and self checkouts
            self.text_box(str(num_cashiers + num_checkouts), x, y, 25, 25)

            # Display statistics about the remaining cashiers

            # Show the total number of normal cashiers
            helpedText = "Cashiers: " + str(num_cashiers)
            self.text_box(helpedText, int(self.displayWidth / 6), 60, width=int(self.displayWidth / 3), height=25)

            # Show the total number of self checkouts
            ipmText = "Self Checkouts: " + str(num_checkouts)
            self.text_box(ipmText, int(self.displayWidth / 2), 60, width=int(self.displayWidth / 3), height=25)

            # Show the total customers inside lines that are not shown
            itemText = "Customers: " + str(num_custs)
            self.text_box(itemText, int(self.displayWidth / 3), 90, width=int(self.displayWidth / 3), height=25)
        # The user isn't hovering over this box
        else:
            # Show a regular text box with details of how many cashiers and checkouts there are
            self.text_box(str(num_cashiers + num_checkouts), x, y, 25, 25)
        pass

    def print_line(self, x, y, cashier_queue=None):
        """ Prints the customer's in line for the cashier

            Precondition:
            - x: The starting x coordinate to print the customer's at
            - y: The starting y coordinate to print the customer's at
            - cashier_queue: The list of customers in line

            Postcondition:
            - Two seperate boxes. The first, which is right next to the cashier,
                shows the current customer being helped, and will slowly disappear over time as it's items
                are checked out. The second is a non interactable block that shows the number of customers
                in line for the current cashier
        """

        # Get the mouse's position
        mouse = pygame.mouse.get_pos()

        # Is the mouse within the confines of the first customer block?
        if x - 5 > mouse[0] > x - 30 and y + 25 > mouse[1] > y:
            # Only do something if there is at least one person in line
            if len(cashier_queue) > 0:
                # Draw a completely white cashier
                pygame.draw.rect(self.screen, (255, 255, 255),
                                 (x - 30, y, 25, 25))

                # Show the current number of item's the the customer has left on top
                itemsText = "Items Left: " + str(round(cashier_queue[0].number_of_items, 2))
                self.text_box(itemsText, int(self.displayWidth / 3), 60, width=int(self.displayWidth / 3), height=25)
        # Print a single customer block that disappears as the number of items it has goes down
        elif len(cashier_queue) > 0:
            # Set transparency by the number of items currently in the queue
            if cashier_queue[-1].number_of_items >= 0 and cashier_queue[-1].total_items > 0:
                # Block goes from white to black
                transparency = int(255 * cashier_queue[-1].number_of_items / cashier_queue[-1].total_items)
            else:
                # In case of weird input, show a completely white block
                transparency = 255
            # Draw a customer block
            try:
                pygame.draw.rect(self.screen, (transparency, transparency, transparency),
                             (x - 30, y, 25, 25))
            except Exception as E:
                pygame.draw.rect(self.screen, (255, 255, 255),
                                 (x - 30, y, 25, 25))
        # If there is more than 1 person in line
        if len(cashier_queue) > 1:
            # Draw a second square to represent the rest of the customers in line
            pygame.draw.rect(self.screen, (255, 255, 255),
                             (x - 30, y - 30, 25, 25))

            # Represent the number of people in line as a string
            lineText = str(len(cashier_queue) - 1)

            # Write these items to screen
            textSurf, textRect = self.textObj(lineText, self.smallFont, self.red)
            textRect.center = ((x - 30 + int(25 / 2)),
                               (y - 30 + int(25 / 2)))
            self.screen.blit(textSurf, textRect)

    def textObj(self, text, t_font, t_color):
        """ Used to get the necessary references to make and print text to screen

            Precondition:
            - text: A string to display; Numbers of any type must be passed through str()
            - t_font: The font to print this text in
            - t_color: The color to show this text with

            Postcondition:
            - The components to write text to screen
        """

        # Render the text using the specified font
        textSurface = t_font.render(text, True, t_color)

        # Return the render, and the rectangle so that people can modify it's location
        return textSurface, textSurface.get_rect()

    def text_box(self, text, x, y, width, height):
        """ Used to quickly display a solid rectangle with text inside of it

            Precondition:
            - text: Text to display; Must be of type string, pass numbers through
                str(number) conversion before sending it here
            - x: The x position of the rectangle and text on screen
            - y: The y position of the rectangle and text on screen
            - width: How wide the background rectangle should be; Does
                not effect the text
            - height: How long the background rectable should be; Does
                not effect the text
            Postcondition:
            - A simple text box on screen
        """

        # Draw a green rectangle
        pygame.draw.rect(self.screen, self.green,
                         (x, y,
                          width, height))

        # Render the text
        textSurf, textRect = self.textObj(text, self.smallFont, self.white)

        # Position the text inside the box
        textRect.center = ((x + (width / 2)),
                           (y + ((height) / 2)))

        # Write the text to screen
        self.screen.blit(textSurf, textRect)

if __name__ == '__main__':
    # Do not allow this function to be called as main.
    pass


"""
This module contains utilities working with Blender collections.
"""

import bpy

from bpybb.utils import active_object

def add_ctrl_empty(name=None):

    bpy.ops.object.empty_add(type="PLAIN_AXES")
    empty_ctrl = active_object()

    if name:
        empty_ctrl.name = f"empty.{name}"
    else:
        empty_ctrl.name = "empty.cntrl"

    return empty_ctrl


import cv2

if __name__ == "__main__":
    model = cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
    face_cascade = cv2.CascadeClassifier(model)
    input_image = cv2.imread('input.jpg')

    scale_coefficient = 0.25
    width = int(input_image.shape[1] * scale_coefficient)
    height = int(input_image.shape[0] * scale_coefficient)
    dimensions = (width, height)

    resized = cv2.resize(input_image, dimensions, interpolation=cv2.INTER_AREA)
    gray_scaled_color = cv2.cvtColor(resized, cv2.COLOR_BGR2GRAY)

    for (x, y, width, height) in face_cascade.detectMultiScale(gray_scaled_color, 1.1, 12):
        red_color = (0, 0, 255)
        cv2.rectangle(resized, (x, y), (x + width, y + height), red_color, 2)

    cv2.imshow('result', resized)
    cv2.waitKey()


import operator

import pandas as pd
import pytest

from .rules import RuleValue

test_data = pd.read_csv("./data/test_data.csv", index_col=0)
RULES = [
    RuleValue(
        sample=test_data.loc["big_light_diamond"].to_dict(),
        comparator=operator.ge,
        value=0,
    ),
    RuleValue(
        sample=test_data.loc["small_light_diamond"].to_dict(),
        comparator=operator.ge,
        value=0,
    ),
]

@pytest.mark.parametrize("rule", RULES)
def test_rule_value(pipeline, rule: RuleValue):
    pred = pipeline.predict(pd.DataFrame([rule.sample]))[0]
    assert rule.comparator(pred, rule.value)


import time as tt
t0=tt.time()
dats=[['google','amazon',],['amazon','google','python','cse'],['cse','google'],['amazon','python'],
      ['cse','amazon','python','google'],['amazon','google','cse','data',]]
sf=[]
from itertools import combinations
import pandas as pd
def pruned(it,k,l):
    subs=combinations(sorted(it),k)
    for itm in subs:
        if itm not in l:
            return False
    return True
def apriori_gen(c,data,minsp,k,l):
    C=[]
    for i in range(0,len(c)):
        itm=[]
        for j in range(i+1,len(c)):
            if c[i][0:(k-1)]==c[j][0:(k-1)]:
                if type(c[i][0:(k-1)])!=tuple:
                    itm=(c[i][0:(k-1)])+(c[i][(k-1)])+(c[j][(k-1)])
                else:
                    itm=c[i][0:(k-1)]+(c[i][(k-1)],)+(c[j][(k-1)],)
                itm=tuple(sorted(itm))
            if pruned(itm,k,l)!=False and itm not in C:
                C.append(itm)

    return C
def apriori(data,minsp):
    global sf
    kdc={}
    fi,sfi=[],[]
    for dat in data:
        for i in range(0,len(dat)):
            if dat[i] not in kdc:
                kdc[dat[i]]=1
            elif dat[i] in dat[0:i]:
                continue
            else:
                kdc[dat[i]]+=1
    for k,v in kdc.items():
                if v>=minsp:
                    fi.append((k,v))
                    sfi.append(k)
    sfi=sorted(sfi)
    sf=fi
    for i in range(len(data)):
        data[i]=tuple(set(sfi).intersection(set(data[i])))
    k=2
    l=[]
    c=[]
    c=combinations(sfi,2)
    for it in c:
        l.append(it)
    c=l
    dic={}
    while len(l)!=0:
        if k>2:
            c=apriori_gen(l,dats,minsp,k-1,l)
        for it in data:
            sub=combinations(it,k)
            subs=[]
            for itms in sub:
                subs.append(tuple(sorted(itms)))
            for itm in c:
                itm=tuple(sorted(itm))
                if itm in subs:
                    #print(itm,"----",subs)
                    if itm not in dic:
                        dic[itm]=1
                    else:
                        dic[itm]+=1
        l=[]
        for key,v in dic.items():
            if v>=minsp:
                fi.append((key,v))
                l.append(key)
        dic={}
        k=k+1
    freq=fi
    data=pd.DataFrame(columns=["items","support"])
    its=[]
    sps=[]
    for i in range(0,len(freq)):
        its.append(str(freq[i][0]))
        sps.append(freq[i][1])
    data["items"]=its
    data["support"]=sps
    return data
import requests as rq
res=rq.get(r"https://raw.githubusercontent.com/stedy/Machine-Learning-with-R-datasets/master/groceries.csv")
datass=[]
for it in res.iter_lines(1000000):
    li=[]
    for itm in it.split():
        li.append(itm)
    datass.append(li)
dii=datass[0:100]
print(apriori(dats,2).sort_values(ascending=False,by="support"))


#python3

"""
This file takes the output of Cello and prints it out to a nice layout.
Important Information to Present:
    Circuit diagram (wire diagram with blocks) - the main circuit diagram file is:
        wiring_grn.svg
    Plasmid maps
    Expected input range and output range
    List of genetic components used to build the plasmid

Notes:
The SVG files should each be their own page.
xfer.png files represent the Hill function - some have wiring included.
srPr gate represents some kind of output measurement.
The PDF and the png files are replicates, you can leave out one and keep the other.

"""

import os
import logging
import shutil
import traceback
import json
from cello_util.plasmid_map.cello_plasmid_mapper import get_cello_plasmid_map_div

"""
Inputs:
    results_dir: (str) The path to the folder containing all the output files
        from Cello.
    scratch_dir: (str) The path to the scratch directory
    user_output_name: (str) The user's output name
    config_info: (dict) Information regarding the html
        base_plasmid_info: (str) fixed vocab - "none", "custom" etc.
Outputs:
    html_result_dict: (dict)
        "result_file_path" : (str) file path to resulting html file.
        "output_directory": (str) path to resulting output_directory in scratch
            dir.

"""
def build_html(results_dir, scratch_dir, user_output_name, config_info):
    """
    There is a variable amount of png files we need to return to the user.
    Should we enforce a limit? (10 currently)
    """
    logging.info("Starting to generate html report.")

    output_directory = os.path.join(scratch_dir, "HTML_Report")
    config_info["scratch_dir"] = scratch_dir
    os.makedirs(output_directory, exist_ok=True)
    #The following function adds png files and javascript files.
    update_static_files(output_directory)

    try:

        out_files_dict = extract_files_from_folder(results_dir)

        num_plasmids_created = out_files_dict["num_plasmids_created"]
        overview_content = '
 ' + str(num_plasmids_created) + \
        " Plasmids Created by Cello. Visualizations provided in the other tabs.
"

        result_file_path = os.path.join(output_directory, 'report.html')

        html_template = open(os.path.join(os.path.dirname(__file__),
            "report_template.html"), "r")
        html_file_str = html_template.read()
        html_template.close()

        path_to_wiring_png_file = out_files_dict['wiring_png_file']

        png_diagram_name = get_name_from_path(path_to_wiring_png_file,
                "wiring_png")
        png_display_name = 'Wiring Diagram'
        #We get the wiring link file from the svg file:
        if out_files_dict["wiring_svg_diagram_found"] == True:
            diagram_link = get_name_from_path(out_files_dict['wiring_svg'])
            shutil.copy2(os.path.join(results_dir, diagram_link),
            os.path.join(output_directory, diagram_link))

        else:
            diagram_link = png_diagram_name

        shutil.copy2(os.path.join(results_dir, png_diagram_name),
        os.path.join(output_directory, png_diagram_name))
        visualization_content = ''
        visualization_content += '
'
        visualization_content += ''.format(diagram_link)
        visualization_content += ''.format(
        png_display_name)
        visualization_content += '
{}

'.format(
        png_display_name)

        #For each truth graph make one of these
        truth_png_files = out_files_dict['truth_png_files']
        truth_pdf_files = out_files_dict['truth_pdf_files']

        #We set the upper limit of different png files to be 10
        k = min(len(truth_png_files), 10)

        for i in range(k):
            truth_graph_dict = truth_png_files[i]

            truth_graph_path = truth_graph_dict['file_path']
            truth_gene_name = truth_graph_dict['gene_name']

            truth_graph_name = get_name_from_path(truth_graph_path,"truth")
            truth_graph_display_name = 'RPU Graph for ' + truth_gene_name

            shutil.copy2(os.path.join(results_dir, truth_graph_name),
            os.path.join(output_directory, truth_graph_name))

            truth_graph_link = truth_graph_name
            #Getting PDF file as a link:
            for i in range(len(truth_pdf_files)):
                pdf_file_dict = truth_pdf_files[i]
                pdf_gene = pdf_file_dict['gene_name']
                if truth_gene_name == pdf_gene:
                    truth_graph_link = get_name_from_path(
                            pdf_file_dict['file_path'] , "truth")
                    shutil.copy2(os.path.join(results_dir, truth_graph_link),
                    os.path.join(output_directory, truth_graph_link))
                    break
            visualization_content += '
'
            visualization_content += ''.format(truth_graph_link)
            visualization_content += ''.format(
            truth_graph_display_name)
            visualization_content += '
{}

'.format(
            truth_graph_display_name)

        #Here add plasmid visualization step - MAPS:
        gbk_files = out_files_dict['gbk_files']

        try:
            plasmid_vis_info = config_info
            gb_plasmid_divs_str = make_plasmid_divs(gbk_files, user_output_name,
                    plasmid_vis_info)
        except:
            logging.critical("Failed to make plasmid_divs")
            gb_plasmid_divs_str = ""
            logging.critical(traceback.print_exc())
        try:
            gb_plasmid_buttons_str = make_plasmid_buttons(gbk_files)
        except:
            gb_plasmid_buttons_str = ""
            logging.critical(traceback.print_exc())

        html_file_str = html_file_str.replace('
Visualization_Content
', visualization_content)
        html_file_str = html_file_str.replace('
Overview_Content
',overview_content)
        html_file_str = html_file_str.replace('{New_Plasmid_Divs}', gb_plasmid_divs_str)
        html_file_str = html_file_str.replace('{New_Plasmid_Buttons}', gb_plasmid_buttons_str)

        f = open(result_file_path, "w")
        f.write(html_file_str)
        f.close()

    except:
        logging.critical("Creation of HTML file failed at some point " + \
                        "in the function build_html (html_design) .")
        result_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"error.html")

    html_result_dict = {
        "result_file_path" : result_file_path,
        "output_directory": output_directory
            }

    return html_result_dict

"""
Inputs:
    full_path_to_folder: (str) The path to the folder containing all the output
        files from Cello.
Outputs:
    out_files_dict: (dict)
        wiring_svg: (str) The full path to the wiring svg file.
        wiring_svg_diagram_found: (bool) True if found, False if not.
        wiring_png_file: (str) The full path to the wiring png file.
        png_diagram_found: (bool) True if found, False if not
        truth_png_files: (list) List of dicts, where each contains name of gene
            and the full path to the png files.
            truth_dict: (dict)
                gene_name: (str) Name of gene
                file_path: (str) Path to file
        truth_png_files_found: (bool) True if found, False if not.
        truth_pdf_files: (list) List of dicts, where each contains name of gene
            and the full path to the pdf files.
            truth_dict: (dict)
                gene_name: (str) Name of gene
                file_path: (str) Path to file
        truth_pdf_files_found: (bool) True if found, False if not.
        gbk_files: (list) List of all paths to gbk files.
        all_return_files: (list of str) The full paths to all the files.

"""
def extract_files_from_folder(results_dir):

    #Getting files to sort through:
    all_files = os.listdir(results_dir)

    out_files_dict = dict()

    #Extracting Circuit Diagram - filename should end with 'wiring_grn.svg':
    wiring_svg_files = []
    wiring_png_files = []
    truth_pdf_files = []
    truth_png_files = []
    gbk_files = []
    wiring_svg_found = False
    wiring_png_files_found = False
    truth_png_files_found = False
    truth_pdf_files_found = False
    plasmid_ape_files_created = 0
    for f in all_files:
        if "wiring_agrn.svg" in f:
            wiring_svg_files.append(os.path.join(results_dir,f))
            wiring_svg_found = True
        elif "truth.png" in f:
            truth_gene_name = get_gene_name_for_truth_graph(f)
            truth_file_info = {"gene_name" : truth_gene_name, 'file_path': f}
            truth_png_files.append(truth_file_info)
            truth_png_files_found = True
        elif "truth.pdf" in f:
            truth_pdf_name = get_gene_name_for_truth_graph(f)
            truth_file_info = {"gene_name" : truth_pdf_name, 'file_path' : f}
            truth_pdf_files.append(truth_file_info)
            truth_pdf_files_found = True
        elif "wiring_agrn.png" in f:
            wiring_png_files.append(os.path.join(results_dir,f))
            wiring_png_files_found = True
        elif ".ape" in f:
            plasmid_ape_files_created += 1
        elif ".gbk" in f:
            gbk_files.append(os.path.join(results_dir,f))
    if wiring_svg_found:
        out_files_dict['wiring_svg'] = wiring_svg_files[0]
        if len(wiring_svg_files) > 1:
            logging.critical("Multiple wiring svg files found- Returning the first one.")
    if wiring_png_files_found:
        out_files_dict['wiring_png_file'] = wiring_png_files[0]
        if len(wiring_png_files) > 1:
            logging.critical("Multiple wiring grn files found- Returning the first one.")

    out_files_dict['wiring_svg_diagram_found'] = wiring_svg_found
    out_files_dict['png_diagram_found'] = wiring_png_files_found
    out_files_dict['truth_pdf_files_found'] = truth_pdf_files_found
    out_files_dict['truth_pdf_files'] = truth_pdf_files
    out_files_dict['truth_png_files_found'] = truth_png_files_found
    out_files_dict['truth_png_files'] = truth_png_files
    all_output_files = wiring_svg_files + truth_png_files + wiring_png_files
    out_files_dict['all_return_files'] = all_output_files
    out_files_dict["num_plasmids_created"] = plasmid_ape_files_created
    out_files_dict["gbk_files"] = gbk_files

    return out_files_dict

"""
Inputs:
    gbk_files: (list) A list of full paths to the gbk files.
    user_output_name: (str)
    plasmid_vis_info: (dict)
        base_plasmid_info: (str) none, custom, etc
Output:
    plasmid_divs_str: (str) A string to insert into report html.
"""
def make_plasmid_divs(gbk_files, user_output_name, plasmid_vis_info):

    #We place basic parameters on the design of the plasmid map:
    base_div_html_fp = os.path.join(os.path.dirname(__file__),
            "plasmid_map/div_svg_template.html")
    config_filepath = os.path.join(os.path.dirname(__file__),
            "plasmid_map/config.json")
    with open(config_filepath, "r") as cf:
        config_dict = json.loads(cf.read())

    if plasmid_vis_info["base_plasmid_info"] == "none":
        #If there are expected to be big CDs, we make the arrow smaller.
        #Instead of 85 percent, it will be 96 percent
        config_dict['js_info']['cds_info']['percent_start'] = 96

    plasmid_divs_str = ''
    #We set a maximum number of files to be made (6):
    k = min(len(gbk_files), 6)
    for i in range(k):
        gb_file = gbk_files[i]
        uniq_dict = {
            "file_num": i,
            "uniq_id": "prfx_" + str(i),
            "svg_id": "svg-" + str(i),
            "svg_name": "svg_" + str(i),
            "tmp_name": "plasmid_tmp_" + str(i),
            "scratch_dir": plasmid_vis_info["scratch_dir"]

                }
        try:
            plasmid_map_dict = get_cello_plasmid_map_div(gb_file,
                    base_div_html_fp, config_filepath, uniq_dict)
        except:
            logging.critical("FAILED TO MAKE VISUALIZATION: {}".format(gb_file))
            logging.critical(traceback.print_exc())
            break
        plasmid_map_div_html = plasmid_map_dict["complete_div_str"]
        plasmid_map_name = plasmid_map_dict["plasmid_name"]
        plasmid_map_div_html = plasmid_map_div_html.replace("Plasmid_Name_Here",
                user_output_name + "_" + plasmid_map_name)
        plasmid_map_div_html = plasmid_map_div_html.replace('id="Plasmid_Div_Id_Here"',
                'id="Plasmid_Map_' + str(i+1) + '"')
        plasmid_map_div_html = plasmid_map_div_html.replace('SVG_ID_HERE','my_svg_' + \
                str(i+1))

        plasmid_divs_str += plasmid_map_div_html + '\n\n\n'

    return plasmid_divs_str

"""
Inputs:
    HTML_Report_dir: (str) The path to the directory
"""
def update_static_files(HTML_Report_dir):
    #Vars (Paths):
    delete_img = "/kb/module/static/delete_img.png"
    reset_img = "/kb/module/static/reset_img.png"
    js_files = [ "/kb/module/static/js/d3-dispatch.v1.min.js",
        "/kb/module/static/js/d3-drag.v1.min.js",
        "/kb/module/static/js/d3-selection.v1.min.js",
        "/kb/module/static/js/d3.min.js"
            ]
    sh_ret = shutil.copyfile(delete_img, os.path.join(HTML_Report_dir,
            "delete_img.png"))
    logging.debug("NEW FILE COPY: {}".format(sh_ret))
    sh_ret = shutil.copyfile(reset_img, os.path.join(HTML_Report_dir,
            "reset_img.png"))
    logging.debug("NEW FILE COPY: {}".format(sh_ret))

    for js_file in js_files:
        js_file_name = js_file.split('/')[-1]
        shutil.copyfile(js_file, os.path.join(HTML_Report_dir, js_file_name))

"""
Inputs:
    gbk_files: (list) A list of full paths to the gbk files.

Output:
    plasmid_buttons_str: (str) A string to insert into report html.
"""
def make_plasmid_buttons(gbk_files):
    plasmid_buttons_str = ''
    k = min(len(gbk_files), 6)
    for i in range(k):
        new_id = "Plasmid_Map_" + str(i+1)
        new_button = '<button class="tablinks" onclick="openTab(event, ' + \
                "'" + new_id + "')" + \
        '">' + new_id.replace("_", " ") + "</button>\n"
        plasmid_buttons_str += new_button

    return plasmid_buttons_str

"""
Inputs:
    filepath: (str) Full path to the file
    typ: (str) Type of file: 'wiring_png' or 'truth'
"""
def get_name_from_path(filepath, typ = None):

    #For now we just return the filename
    return filepath.split('/')[-1]

"""
Input:
    filename: (str) Just the filename (not filepath). Getting name of gene from cello's production
    of a filename. Normally it looks like: job_1576197897501_A000_BFP_truth.png, we need "BFP" so we
     split by "_" and take the fourth index until the last index

"""
def get_gene_name_for_truth_graph(filename):

    return "".join((filename.split("_"))[3:-1])

def html_design_test():
    this_dir = os.path.dirname(os.path.realpath(__file__))
    gbk_files = [os.path.join(this_dir,"tst/job_1581723951170_A000_plasmid_circuit_P000.gbk"),
            os.path.join(this_dir,"tst/job_1581723951170_A000_plasmid_output_P000.gbk")]
    user_output_name = ""
    plasmid_vis_info = {
        "base_plasmid_info": "custom"
            }
    gb_plasmid_divs_str = make_plasmid_divs(gbk_files, user_output_name, plasmid_vis_info)

#if __name__ == "__main__":
#    html_design_test()