import logging
import os
import sys
import gspread
from oauth2client.service_account import ServiceAccountCredentials

from session import Session
from userSession import UserSession

from telegram.ext import Updater, CommandHandler, CallbackContext, MessageHandler, Filters
from telegram import Update, ReplyKeyboardMarkup, ReplyKeyboardRemove

# Enabling logging
logging.basicConfig(level=logging.INFO,
                    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
logger = logging.getLogger()

# Getting mode, so we could define run function for local and Heroku setup
mode = os.getenv("MODE")
TOKEN = os.getenv("TOKEN")
if mode == "dev":
    def run(updater):
        updater.start_polling()
elif mode == "prod":
    def run(updater):
        PORT = int(os.environ.get("PORT", "8443"))
        HEROKU_APP_NAME = os.environ.get("HEROKU_APP_NAME")
        # Code from https://github.com/python-telegram-bot/python-telegram-bot/wiki/Webhooks#heroku
        updater.start_webhook(listen="0.0.0.0",
                              port=PORT,
                              url_path=TOKEN)
        updater.bot.set_webhook("https://{}.herokuapp.com/{}".format(HEROKU_APP_NAME, TOKEN))
else:
    logger.error("No MODE specified!")
    sys.exit(1)

# Initialize the client for google sheet API
scope = ['https://spreadsheets.google.com/feeds',
         'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name('client-secret.json', scope)
client = gspread.authorize(creds)

#startbotSession
session = Session()
userSession = UserSession()

startMessage = "Hi! Welcome to my trivia bot!\nTo start a game, use the /startGame command. \nTo join a game, use the /join command! \n\n Please be gentle. I am fragile"
userGuide = "Yo! Need help? \n /begin - start the game \n /addQuestion - add question to your game \n /endGame - end the game \n /players - get a list of the players who are in the game \n\nYour group name is: \n{}"

addQuestionBySheetGuide = "Please follow these steps precisely. If not I may die hahaha.\nStep 1:\nShare the google sheet with my email trivaiquestionloader@triviatelegrambot.iam.gserviceaccount.com\nStep 2:\nSend me the URL!\n\nJust a reminder that the question sheet has to follow the stipulated format!"

invalidCommandMessage = "You have no access to this command! Didnt I ask you to be gentle? \n/restart to try again if you are stuck"

gameMasterKeyboard = ReplyKeyboardMarkup([["/begin", "/addQuestion"], ["/players", "/questions"], ["/addQnByGoogleSheet"], ["/endGame"]])
gameMasterStartGameKeyboard = ReplyKeyboardMarkup([["/next", "/burden"], ["/endGame"]])

playerInGameKeyboard = ReplyKeyboardMarkup([["/exit"]])

# Session Values
# /join - Joins the game
# /startGame - Starts a new game
# /gamemaster - gamemaster - you are the gamemaster with control of your game
# /chooseRightAnswer - gamemaster - view the answers and choose
# /givepoints - gamemaster - give points for answers you think are correct
# /addQuestion - gamemaster - add questions to game session
# /question - player - player in a game session

# Routes
# /join -> /question
# /startGame -> /gamemaster -> {/gamemaster, /chooseRightAnswer, /givepoints, /addQuestion}

gameMasterSessionsKeys = ["/gamemaster", "/chooseRightAnswer", "/givepoints", "/addQuestion"]

# General Command
def start_handler(update: Update, context: CallbackContext):
    username = update.effective_user["username"]
    logger.info("User {} started bot".format(update.effective_user["username"]))
    userSession.end_session(username)
    context.bot.sendMessage(
        chat_id=update.effective_user["id"], text=startMessage, reply_markup=ReplyKeyboardMarkup([["/startGame"], ["/join"]]))

def join_handler(update: Update, context: CallbackContext):
    username = update.effective_user["username"]
    if isAGameMaster(userSession.get_last_command(username)):
        context.bot.sendMessage(
            chat_id=update.effective_user["id"], text="You are currently hosting a game. To start a new game, end the current game using /endGame")
    logger.info("User {} wants to join a game".format(update.effective_user["username"]))
    userSession.start_session(username, "/join")
    context.bot.sendMessage(
        chat_id=update.effective_user["id"], text="Please enter the name of the group you would like to join", reply_markup=ReplyKeyboardMarkup([["/restart"]]))

def restart_handler(update: Update, context: CallbackContext):
    username = update.effective_user["username"]
    logger.info("User {} went back to the start".format(update.effective_user["username"]))
    userSession.end_session(username)
    context.bot.sendMessage(
        chat_id=update.effective_user["id"], text=startMessage, reply_markup=ReplyKeyboardMarkup([["/startGame"], ["/join"]]))

def startGame_handler(update: Update, context: CallbackContext):
    username = update.effective_user["username"]
    if isAGameMaster(userSession.get_last_command(username)):
        context.bot.sendMessage(
            chat_id=update.effective_user["id"], text="You are currently hosting a game. To start a new game, end the current game using /endGame")
    logger.info("User {} would like to start game".format(update.effective_user["username"]))
    userSession.start_session(username, "/startGame")
    context.bot.sendMessage(
        chat_id=update.effective_user["id"], text="How would you like to name the group?", reply_markup=ReplyKeyboardMarkup([["/restart"]]))

# Non command handler
def answer_handler(update: Update, context: CallbackContext):
    username = update.effective_user["username"]
    userInput = update.message.text
    chatId = update.effective_user["id"]

    if(userSession.get_last_command(username) == "/join"):
        #userInput should be the game name
        game = session.getGamebyGameName(userInput)
        if game:
            game.addPlayer(username, chatId)
            logger.info("User {} joined the game {}".format(update.effective_user["username"], userInput))
            userSession.update_session(username, "/question")
            userSession.add_passing_arguments(username,[userInput])
            context.bot.sendMessage(
                chat_id=update.effective_user["id"], text="You have successfully joined the game. Please wait for the game to start", reply_markup=playerInGameKeyboard)
            context.bot.sendMessage(
                chat_id=game.getOwnerId(), text="{} joined the game.".format(username))

        else:
            context.bot.sendMessage(
                chat_id=update.effective_user["id"], text="The game does not exist. Please try again. If you would like to start a game, you can use /startGame", reply_markup=ReplyKeyboardMarkup([["/restart"]]))

    elif(userSession.get_last_command(username) == "/question"):
        gameName = userSession.get_passing_arguments(username)[0]
        game = session.getGamebyGameName(gameName)
        if game.hasStarted():
            # userInput is the answer to the question
            # store answers somewhere
            game.addAnswer(username, userInput)
            context.bot.sendMessage(
                    chat_id=game.getOwnerId(), text="{} has answered the question".format(username))
            context.bot.sendMessage(
                    chat_id=update.effective_user["id"], text="Good Answer! Wait to see if you are right.", reply_markup=playerInGameKeyboard)
            if(game.hasAllAnswered()):
                context.bot.sendMessage(
                    chat_id=game.getOwnerId(), text="All answers are in! You can move on to the /next section and choose who gets the right answer!")
        else:
            context.bot.sendMessage(
                    chat_id=update.effective_user["id"], text="Game havent start yet...", reply_markup=playerInGameKeyboard)

    elif(userSession.get_last_command(username) == "/startGame"):
        #userInput should be the new game name
        validGameSession = session.addSession(username, chatId, userInput)
        if validGameSession:
            userSession.update_session(username, "/gamemaster")
            userSession.add_passing_arguments(username,[userInput])
            context.bot.sendMessage(
                chat_id=update.effective_user["id"], text=userGuide.format(userInput), reply_markup=gameMasterKeyboard)
        else:
            context.bot.sendMessage(
                chat_id=update.effective_user["id"], text="Game name already exist. Please use another name.", reply_markup=ReplyKeyboardMarkup([["/restart"]]))

    elif(userSession.get_last_command(username) == "/addQuestion"):
        #userInput should be a question
        gameName = userSession.get_passing_arguments(username)[0]
        validAddQuestion = session.addQuestion(username, gameName, userInput)
        userSession.update_session(username, "/gamemaster")
        context.bot.sendMessage(
                chat_id=update.effective_user["id"], text="Question has been added. To see your questions, use /questions", reply_markup=gameMasterKeyboard)

    elif(userSession.get_last_command(username) == "/addQuestionSheet"):
        #userInput should be the link to the sheet
        gameName = userSession.get_passing_arguments(username)[0]
        sheet = client.open_by_url(userInput).get_worksheet(0)
        listOfQuestions = sheet.get_all_records()
        validGame = session.getGamebyOwner(username)
        if validGame:
            for questionJ in listOfQuestions:
                qn = questionJ['Questions']
                validGame.addQuestion(username, qn)
            userSession.update_session(username, "/gamemaster")
            context.bot.sendMessage(
                chat_id=update.effective_user["id"], text="Question from sheet has been added! To see your questions, use /questions", reply_markup=gameMasterKeyboard)

        else:
            logger.info("User {} tried to add questions when he/she is not allowed to!").format(username)
            context.bot.sendMessage(
                chat_id=update.effective_user["id"], text=invalidCommandMessage)

    elif(userSession.get_last_command(username) == "/givepoints"):
        #userInput should be a the user with the correct answer
        gameName = userSession.get_passing_arguments(username)[0]
        game = session.getGamebyGameName(gameName)
        game.addPointsToUser(userInput)
        playerId = game.getPlayerId(userInput)
        context.bot.sendMessage(
                chat_id=playerId, text="Great job! +1 point", reply_markup=playerInGameKeyboard)
        context.bot.sendMessage(
                chat_id=update.effective_user["id"], text="Anymore correct answer? if not /next", reply_markup=ReplyKeyboardMarkup(game.getAnswerKeyboard()))

    else:
        context.bot.sendMessage(
                chat_id=update.effective_user["id"], text="Invalid input. Please use /restart if you see this too many times.", reply_markup=ReplyKeyboardMarkup([["/restart"]]))

# Game master command
def addQuestion_handler(update: Update, context: CallbackContext):
    username = update.effective_user["username"]
    logger.info("User {} would like to add question to the game".format(update.effective_user["username"]))
    if (userSession.get_last_command(username) == "/gamemaster"):
        userSession.update_session(username, "/addQuestion")
        context.bot.sendMessage(
            chat_id=update.effective_user["id"], text="Please type in your question. Remember to add the question mark!", reply_markup=ReplyKeyboardRemove())
    else:
        context.bot.sendMessage(
            chat_id=update.effective_user["id"], text=invalidCommandMessage, reply_markup=ReplyKeyboardMarkup([["/restart"]]))

def addQuestionBySheet_handler(update: Update, context: CallbackContext):
    username = update.effective_user["username"]
    logger.info("User {} would like to add question using a google sheet".format(username))
    if (userSession.get_last_command(username) == "/gamemaster"):
        userSession.update_session(username, "/addQuestionSheet")
        context.bot.sendMessage(
            chat_id=update.effective_user["id"], text=addQuestionBySheetGuide, reply_markup=ReplyKeyboardRemove())
    else:
        context.bot.sendMessage(
            chat_id=update.effective_user["id"], text=invalidCommandMessage, reply_markup=ReplyKeyboardMarkup([["/restart"]]))

def seePlayers_handler(update: Update, context: CallbackContext):
    username = update.effective_user["username"]
    logger.info("User {} would like to see the players".format(update.effective_user["username"]))
    if (userSession.get_last_command(username) == "/gamemaster"):
        game = session.getGamebyOwner(username)
        players = game.printPlayersInGame()
        context.bot.sendMessage(
            chat_id=update.effective_user["id"], text=players, reply_markup=gameMasterKeyboard)
    else:
        context.bot.sendMessage(
            chat_id=update.effective_user["id"], text="You cannot do this", reply_markup=ReplyKeyboardMarkup([["/restart"]]))

def seeQuestions_handler(update: Update, context: CallbackContext):
    username = update.effective_user["username"]
    logger.info("User {} would like to see the questions".format(update.effective_user["username"]))
    if (userSession.get_last_command(username) == "/gamemaster"):
        game = session.getGamebyOwner(username)
        questions = game.printQuestionsInGame()
        context.bot.sendMessage(
            chat_id=update.effective_user["id"], text=questions, reply_markup=gameMasterKeyboard)
    else:
        context.bot.sendMessage(
            chat_id=update.effective_user["id"], text="You cannot do this", reply_markup=ReplyKeyboardMarkup([["/restart"]]))

def exit_handler(update: Update, context: CallbackContext):
    username = update.effective_user["username"]
    if userSession.get_last_command(username) == "/gamemaster":
        context.bot.sendMessage(
                chat_id=update.effective_user["id"], text="dude... you are the game master", reply_markup=gameMasterKeyboard)
    else:
        gamename = userSession.get_passing_arguments(username)[0]
        game = session.getGamebyGameName(gamename)
        game.removePlayer(username)
        context.bot.sendMessage(
                chat_id=game.getOwnerId(), text="Player {} has left the game".format(username))
        context.bot.sendMessage(
                chat_id=update.effective_user["id"], text="Thank you for playing", reply_markup=ReplyKeyboardMarkup([["/start"]]))

def begin_handler(update: Update, context: CallbackContext):
    username = update.effective_user["username"]
    if(userSession.get_last_command(username) == "/gamemaster"):
        logger.info("User {} would like start the game".format(update.effective_user["username"]))
        game = session.getGamebyOwner(username)
        if game.hasQuestions() and game.hasPlayers():
            listOfPlayers = game.getPlayerList()
            sendMessageToAllPlayers(context, listOfPlayers, "The game is about to beign!")
            game.startGame()
            context.bot.sendMessage(
                    chat_id=update.effective_user["id"], text="Press /next to start with the questions", reply_markup=gameMasterStartGameKeyboard)
        else:
            if not game.hasQuestions():
                context.bot.sendMessage(
                        chat_id=update.effective_user["id"], text="You do not have any questions! Use /addQuestion to add questions to your game!")
            elif not game.hasPlayers():
                context.bot.sendMessage(
                        chat_id=update.effective_user["id"], text="You do not have any players!! Get your friends to join the game!! Your game name is: \n{}".format(game.getGameName()))
            else:
                context.bot.sendMessage(
                        chat_id=update.effective_user["id"], text="Idk what happened that you cannot start hahaha. Make sure you have questions and players!")

    else:
        context.bot.sendMessage(
                chat_id=update.effective_user["id"], text="You have no access to this", reply_markup=ReplyKeyboardMarkup([["/start"]]))

def burden_handler(update: Update, context: CallbackContext):
    username = update.effective_user["username"]
    if isAGameMaster(userSession.get_last_command(username)):
        logger.info("User {} would like to check for burden".format(username))
        game = session.getGamebyOwner(username)

        if(game.hasStarted()):
            if(game.hasAllAnswered()):
                context.bot.sendMessage(chat_id=update.effective_user["id"], text="Everyone has answered. You can move on with /next")
            else:
                listOfBurdens = game.getListOfUnansweredPlayersForCurrentQuestion()
                sendMessageToAllPlayers(context, listOfBurdens, "Don't be a burden. Faster answer pls")
                context.bot.sendMessage(
                    chat_id=update.effective_user["id"], text=game.printListOfPlayers(listOfBurdens, "Burdens:"))
        else:
            context.bot.sendMessage(chat_id=update.effective_user["id"], text="Game hasnt even started... Use /begin to start the game")

    else:
        context.bot.sendMessage(
                chat_id=update.effective_user["id"], text="You have no access to this")

def next_handler(update: Update, context: CallbackContext):
    username = update.effective_user["username"]
    if(userSession.get_last_command(username) == "/gamemaster"):
        game = session.getGamebyOwner(username)
        if(not game.isLastQn()):
            game.addAnswerArr()
            question = game.getCurrentQuestion()
            listOfPlayers = game.getPlayerList()
            for player in listOfPlayers:
                playerChatId = player.getChatId()
                context.bot.sendMessage(
                    chat_id=playerChatId, text=question, reply_markup=playerInGameKeyboard)
            userSession.update_session(username, "/chooseRightAnswer")
            context.bot.sendMessage(
                    chat_id=update.effective_user["id"], text="Question: {} \nWait for everyone to answer before pressing /next".format(question), reply_markup=gameMasterStartGameKeyboard)
        else:

            context.bot.sendMessage(
                    chat_id=update.effective_user["id"], text="You have reached the last question", reply_markup=ReplyKeyboardMarkup([["/endGame"]]))
    elif (userSession.get_last_command(username) == "/chooseRightAnswer"):
        game = session.getGamebyOwner(username)
        userSession.update_session(username, "/givepoints")
        answers = game.printAnswer()
        context.bot.sendMessage(
                    chat_id=update.effective_user["id"], text="These are the answers")
        context.bot.sendMessage(
                    chat_id=update.effective_user["id"], text=answers, reply_markup=ReplyKeyboardMarkup(game.getAnswerKeyboard()))
        context.bot.sendMessage(
                    chat_id=update.effective_user["id"], text="Pick the name with the correct answer")

    elif (userSession.get_last_command(username) == "/givepoints"):
        game = session.getGamebyOwner(username)
        game.nextQuestion()
        userSession.update_session(username, "/gamemaster")
        listOfPlayers = game.getPlayerList()
        for player in listOfPlayers:
            playerChatId = player.getChatId()
            context.bot.sendMessage(
                chat_id=playerChatId, text="The next question is about to begin", reply_markup=playerInGameKeyboard)
        context.bot.sendMessage(
                chat_id=update.effective_user["id"], text="Press /next for the next question", reply_markup=gameMasterStartGameKeyboard)

    else:
        context.bot.sendMessage(
                chat_id=update.effective_user["id"], text="You have no access to this")

def endGame_handler(update: Update, context: CallbackContext):
    username = update.effective_user["username"]
    if isAGameMaster(userSession.get_last_command(username)):
        game = session.getGamebyOwner(username)
        listOfPlayers = game.getPlayerList()
        for player in listOfPlayers:
            playerChatId = player.getChatId()
            context.bot.sendMessage(
                chat_id=playerChatId, text="The game session has ended", reply_markup=ReplyKeyboardMarkup([["/start"]]))
            userSession.end_session(player.getName())
        players = game.printPlayersInGame()
        game.endGame()
        session.endSession(username)
        userSession.end_session(username)
        context.bot.sendMessage(
                chat_id=update.effective_user["id"], text="Thank you for hosting! Here are the final score!\n" + players , reply_markup=ReplyKeyboardMarkup([["/start"]]))
    else:
        context.bot.sendMessage(
                chat_id=update.effective_user["id"], text="You have no access to this")

# Util Function
def sendMessageToAllPlayers(context: CallbackContext, listOfPlayers, message):
    validSendMessage = False
    for player in listOfPlayers:
        playerChatId = player.getChatId()
        context.bot.sendMessage(
            chat_id=playerChatId, text=message, reply_markup=ReplyKeyboardMarkup([["/start"]]))
        validSendMessage = True
    return validSendMessage

def isAGameMaster(sessionKey):
    return sessionKey in gameMasterSessionsKeys

def print_handler(update: Update, context: CallbackContext):
    username = update.effective_user["username"]
    context.bot.sendMessage(
                    chat_id=update.effective_user["id"], text=userSession.to_string(), reply_markup=ReplyKeyboardMarkup([["/endGame"]]))

if __name__ == '__main__':
    logger.info("Starting bot")
    updater = Updater(TOKEN, use_context=True)

    # General Commands
    updater.dispatcher.add_handler(CommandHandler("start", start_handler))
    updater.dispatcher.add_handler(CommandHandler("join", join_handler))
    updater.dispatcher.add_handler(CommandHandler("startGame", startGame_handler))
    updater.dispatcher.add_handler(CommandHandler("restart", restart_handler))

    # Player Commands
    updater.dispatcher.add_handler(CommandHandler("exit", exit_handler))

    # Game master Commands
    updater.dispatcher.add_handler(CommandHandler("questions", seeQuestions_handler))
    updater.dispatcher.add_handler(CommandHandler("addQuestion", addQuestion_handler))
    updater.dispatcher.add_handler(CommandHandler("players", seePlayers_handler))
    updater.dispatcher.add_handler(CommandHandler("begin", begin_handler))
    updater.dispatcher.add_handler(CommandHandler("next", next_handler))
    updater.dispatcher.add_handler(CommandHandler("endGame", endGame_handler))
    updater.dispatcher.add_handler(CommandHandler("burden", burden_handler))
    updater.dispatcher.add_handler(CommandHandler("addQnByGoogleSheet", addQuestionBySheet_handler))
    updater.dispatcher.add_handler(MessageHandler(Filters.text, answer_handler))

    # Debug command
    updater.dispatcher.add_handler(CommandHandler("print", print_handler))

    run(updater)


"""splits data into training, dev, and test sets.

Example usage::

    >>> import numpy as np
    >>> from hansardparser.plenaryparser.classify.split import train_dev_test_split
    >>> data = np.unique(np.random.randint(0, high=100000, size=5000))
    >>> seed = 759388
    >>> sizes = {'train_size': 0.8, 'test_size': 0.2}
    >>> out_path = './'
    >>> splits = train_dev_test_split(data, sizes, random_state=seed)
    >>> save_splits(splits, out_path, fmt='%i')

"""

import os
import numpy as np
from sklearn.model_selection import train_test_split

def train_dev_test_split(data: list, sizes: dict = None, **kwargs) -> dict:
    """splits data into training, development (optional), and test sets.

    Wrapper to sklearn.model_selection.train_test_split.

    Arguments:

        data: list-like iterable of examples to be passed as the *arrays
            argument in sklearn.model_selection.train_test_split.

        sizes: dict indicating what fraction of the examples should be in the
            training, development, and test sets. dict keys must be
            "train_size", "dev_size" (optional), and "test_size". Values must
            sum to 1.0. If "dev_size" key is not given, data is only split
            into a training set and test seet.
            Default::

                {'train_size': 0.6, 'dev_size': 0.2, 'test_size': 0.2}

        **kwargs: keyword arguments to be passed to
            sklearn.model_selection.train_test_split.

    Returns:

        dict: {'train': [train example], 'dev': [dev example], 'test': [test
            example]}. dict containing arrays of training examples, development
            examples, and test examples.
    """
    if sizes is None:
        sizes = {'train_size': 0.6, 'dev_size': 0.2, 'test_size': 0.2}
    assert 'train_size' in sizes and 'test_size' in sizes, "sizes must contain 'train_size' and 'test_size' keys."
    assert all(
        [k in ['train_size', 'dev_size', 'test_size']
         for k in sizes]), "only valid keys for sizes arg are train_size, dev_size, and test_size."
    assert round(sum(sizes.values()), 5) == 1.0, f"sizes values must sum to 1.0, but sum({sizes}) = {sum(sizes.values())}."
    # assert (len(sizes) == 2 and )
    if 'dev_size' in sizes:
        assert len(sizes) == 3
        train_ids, other_ids = train_test_split(
            data,
            train_size=sizes['train_size'],
            test_size=sizes['dev_size'] + sizes['test_size'],
            **kwargs)
        dev_ids, test_ids = train_test_split(
            other_ids,
            train_size=sizes['dev_size'] / (sizes['dev_size'] + sizes['test_size']),
            test_size=sizes['test_size'] / (sizes['dev_size'] + sizes['test_size']),
            **kwargs)
        splits = {'train': train_ids, 'dev': dev_ids, 'test': test_ids}
    else:
        train_ids, test_ids = train_test_split(
            data, train_size=sizes['train_size'], test_size=sizes['test_size'], **kwargs)
        splits = {'train': train_ids, 'test': test_ids}
    return splits

def save_splits(splits: dict, path: str, **kwargs) -> None:
    """saves data splits to file.

    Arguments:

        splits (dict): dict containing the data splits (e.g. return from
            split(). Keys are name of split (e.g. 'train', 'dev', 'test').
            Values should be numpy arrays.
        path (str): directory to save data splits.
        **kwargs: keyword arguments to pass to np.savetxt
    """
    if not os.path.isdir(path):
        os.mkdir(path)
    for split, data in splits.items():
        this_path = os.path.join(path, split + '.txt')
        np.savetxt(this_path, data, **kwargs)
    return None


import pygame
import time
from pygame.locals import *
from sys import exit

import palavras

pygame.init()
pygame.font.init()

largura = 640
altura = 480

qtd_jogador = 1
jogador01_responde = True
erros = 0
acertos = 0
acertou_palavra = False
nivel_jogo = 1

pontos_jogador01 = 0
pontos_jogador02 = 0

fonte_titulos = pygame.font.Font(None, 50)
fonte_textos = pygame.font.Font(None, 30)
fonte_nivel = pygame.font.Font(None, 20)
fonte_info = pygame.font.Font(None, 25)
fonte_letras = pygame.font.Font(None, 40)
fonte_placar = pygame.font.Font(None, 50)

fonte_venceu_perdeu = pygame.font.Font(None, 100)

texto_deve_ditar_palavra = ''

fundo_img = pygame.image.load("assets/fundo.jpg")
fundo = fundo_img.get_rect()

fundo_menu_img = pygame.image.load("assets/fundo_menu.jpg")
fundo_menu = fundo_menu_img.get_rect()

forca_status_img =  pygame.image.load("assets/forca_erro_0.png")
forca_status = forca_status_img.get_rect(right=620, top=100)

placar_img = pygame.image.load("assets/placar.png")
placar = placar_img.get_rect(right=620, top=10)

jogador01_img = pygame.image.load("assets/jogador01.png")
jogador01 = jogador01_img.get_rect(left=(390), top=30)

jogador02_img = pygame.image.load("assets/jogador_maquina.png")
jogador02 = jogador02_img.get_rect(right=610, top=30)

jogador01_digita_palavra_img = pygame.image.load("assets/img_jogador01_digita_palavra.png")
jogador01_digita_palavra = jogador01_digita_palavra_img.get_rect(left=(100), top=80)

jogador02_digita_palavra_img = pygame.image.load("assets/img_jogador02_digita_palavra.png")
jogador02_digita_palavra = jogador02_digita_palavra_img.get_rect(left=(100), top=80)

tela = pygame.display.set_mode((largura, altura))
pygame.display.set_caption('Jogo da Forca')

msg_resultado_img = pygame.image.load("assets/img_ganhou.png")
msg_resultado = msg_resultado_img.get_rect(center=[largura/2-30, altura/2-50])

msg_indica_jogador_img = pygame.image.load("assets/img_indica_jogador01.png")
msg_indica_jogador = msg_indica_jogador_img.get_rect(center=[largura/2-100, altura/2-100])

btn_iniciar_img = pygame.image.load("assets/btn_iniciar.png")
btn_iniciar = btn_iniciar_img.get_rect(center=[largura/2, altura/2+10])

btn_config_img = pygame.image.load("assets/btn_config.png")
btn_config = btn_config_img.get_rect(center=[largura/2, (altura/2)+70])

btn_home_img = pygame.image.load("assets/btn_home_40x40.png")
btn_home = btn_home_img.get_rect(right=70, top=420)

btn_reiniciar_img =  pygame.image.load("assets/btn_reiniciar_40x40.png")
btn_reiniciar = btn_reiniciar_img.get_rect(right=120, top=420)

btn_info_img =  pygame.image.load("assets/btn_info_40x40.png")
btn_info = btn_info_img.get_rect(right=620, top=420)

btn_menu_img = pygame.image.load("assets/btn_menu.png")
btn_menu = btn_menu_img.get_rect(center=[largura/2, (altura/2)+190])

btn_proxima_img = pygame.image.load("assets/btn_proxima.png")
btn_proxima = btn_proxima_img.get_rect(center=[largura/2, (altura/2)+130])

btn_home_fim_jogo = pygame.Rect((largura / 2) - 70, 360, 140, 40)
btn_reiniciar_fim_jogo = pygame.Rect((largura / 2) - 70, 410, 140, 40)

btn_jogador_vs_maquina_img = pygame.image.load("assets/btn_jogador_vs_maquina.png")
btn_jogador_vs_maquina = btn_jogador_vs_maquina_img.get_rect(left=50, top=130)

btn_jogador_vs_jogador_img = pygame.image.load("assets/btn_jogador_vs_jogador.png")
btn_jogador_vs_jogador = btn_jogador_vs_jogador_img.get_rect(left=350, top=130)

btn_continuar_img = pygame.image.load("assets/btn_continuar.png")
btn_continuar = btn_continuar_img.get_rect(center=[largura/2, (altura/2)+130])

btn_gravar_img = pygame.image.load("assets/btn_gravar.png")
btn_gravar = btn_gravar_img.get_rect(left=40, top=400)

fade_img = pygame.Surface((largura, altura)).convert_alpha()
fade = fade_img.get_rect()
fade_img.fill((0,0,0))
fade_alpha = 255

def carrega_palavra():
    if qtd_jogador == 1:
        ifem = '-'
        global palavra_selecionada
        global nivel_jogo
        global pontos_jogador01
        global estado_atual_enigma
        global qtd_ifens_na_palavra
        if palavra_selecionada == '':
            if pontos_jogador01 < 4:
                nivel_jogo = 1
            elif pontos_jogador01 < 7:
                nivel_jogo = 2
            else:
                nivel_jogo = 3

            palavra_selecionada = palavras.seleciona_palavra(nivel_jogo)
            estado_atual_enigma = ["_"] * len(palavra_selecionada)

            if ifem in palavra_selecionada:
                for i in range(len(palavra_selecionada)):
                    if ifem == palavra_selecionada[i]:
                        estado_atual_enigma[i] = ifem
                        qtd_ifens_na_palavra +=1

def limpar_variaveis():
    global erros
    global acertos
    global letras_digitadas
    global palavra_selecionada
    global qtd_ifens_na_palavra
    global lancar_ponto_jog01
    global lancar_ponto_jog02
    erros = 0
    acertos = 0
    letras_digitadas = ''
    palavra_selecionada = ''
    lancar_ponto_jog01 = True
    lancar_ponto_jog02 = True
    qtd_ifens_na_palavra =0

def click_menu():
    audio = pygame.mixer.Sound("assets/audios/menu-click.wav")
    audio.set_volume(0.2)
    audio.play()

audio_acertou = pygame.mixer.Sound("assets/audios/acertou.wav")
audio_errou = pygame.mixer.Sound("assets/audios/errou.wav")

def audio_venceu():
    audio = pygame.mixer.Sound("assets/audios/fim_venceu.mp3")
    audio.set_volume(0.3)
    audio.play()

def audio_perdeu():
    audio = pygame.mixer.Sound("assets/audios/fim_perdeu.wav")
    audio.set_volume(0.3)
    audio.play()

text = ''

font = pygame.font.SysFont(None, 50)

img = font.render(text, True, (255, 200, 0))

rect = img.get_rect()
rect.topleft = (100, 240)
cursor = pygame.Rect(rect.topright, (3, rect.height))

palavra_selecionada = ''

palavra_enigma = ''
letras_digitadas = ''

letra_ja_digitada = False
lancar_ponto_jog01 = True
lancar_ponto_jog02 = True

qtd_ifens_na_palavra = 0

cena = "menu"
fps = pygame.time.Clock()

trilha = pygame.mixer.Sound("assets/audios/trilha.mp3")
trilha.set_volume(0.5)
trilha.play(-1)

while True:

    if cena == "jogo":

        carrega_palavra()

        trilha.set_volume(0.5)

        if erros < 1:
            forca_status_img =  pygame.image.load("assets/forca_erro_0.png")

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

            if event.type == pygame.KEYDOWN:
                letra = event.unicode.upper()

                if letra in letras_digitadas:
                   letra_ja_digitada = True
                else:
                    letras_digitadas += f'{letra} '
                    letra_ja_digitada = False
                    if letra in palavra_selecionada:
                        for i in range(len(palavra_selecionada)):
                            if letra == palavra_selecionada[i]:
                                estado_atual_enigma[i] = letra
                                acertos +=1
                    else:
                        erros+=1
                        if erros == 1:
                            forca_status_img =  pygame.image.load("assets/erro_1.png")
                        elif erros == 2:
                            forca_status_img =  pygame.image.load("assets/erro_2.png")
                        elif erros == 3:
                            forca_status_img =  pygame.image.load("assets/erro_3.png")
                        elif erros == 4:
                            forca_status_img =  pygame.image.load("assets/erro_4.png")
                        elif erros == 5:
                            forca_status_img =  pygame.image.load("assets/erro_5.png")
                        elif erros == 6:
                            forca_status_img =  pygame.image.load("assets/erro_6.png")

            if event.type == pygame.MOUSEBUTTONDOWN:
                if btn_home.collidepoint(event.pos):
                    fade_alpha = 255
                    click_menu()
                    erros = 0
                    acertos = 0
                    estado_atual_enigma = ["_"] * len(palavra_selecionada)
                    letras_digitadas = ''
                    palavra_selecionada = ''
                    qtd_ifens_na_palavra =0
                    cena = "menu"

            if event.type == pygame.MOUSEBUTTONDOWN:
                if btn_reiniciar.collidepoint(event.pos):
                    fade_alpha = 255
                    click_menu()
                    limpar_variaveis()
                    carrega_palavra()
                    cena = "jogo"

            if erros >= 6:
                if lancar_ponto_jog02:
                    if qtd_jogador == 1:
                        pontos_jogador02 +=1
                    elif qtd_jogador == 2:
                        if jogador01_responde:
                            pontos_jogador02 +=1
                        else:
                            pontos_jogador01 +=1

                lancar_ponto_jog02 = False
                acertou_palavra = False
                fade_alpha = 255
                if qtd_jogador == 1:
                    if pontos_jogador02 < 10:
                        cena = "fim_partida"
                    else:
                        cena = "fim_jogo"
                else:

                    if pontos_jogador01 == 10 or pontos_jogador01 == 10:
                        cena = "fim_jogo"
                    else:
                        cena = "fim_partida"

            if acertos == (len(palavra_selecionada)-qtd_ifens_na_palavra) and palavra_selecionada != '':
                if lancar_ponto_jog01:
                    if qtd_jogador == 1:
                        pontos_jogador01 +=1
                    elif qtd_jogador == 2:
                        if jogador01_responde:
                            pontos_jogador01 +=1
                            msg_indica_jogador_img = pygame.image.load("assets/img_indica_jogador01.png")
                        else:
                            pontos_jogador02 +=1
                            msg_indica_jogador_img = pygame.image.load("assets/img_indica_jogador02.png")

                lancar_ponto_jog01 = False
                acertou_palavra = True
                fade_alpha = 255
                if qtd_jogador == 1:

                    if pontos_jogador01 < 10:
                        cena = "fim_partida"
                    else:
                        cena = "fim_jogo"
                else:

                    if pontos_jogador01 == 10 or pontos_jogador01 == 10:
                        cena = "fim_jogo"
                    else:
                        cena = "fim_partida"

        if fade_alpha > 0:
            fade_alpha -= 15
            fade_img.set_alpha(fade_alpha)

        tela.fill((255,200,0))

        tela.blit(fundo_img, fundo)

        if jogador01_responde:
            tela.blit(jogador01_digita_palavra_img, jogador01_digita_palavra)
        else:
            tela.blit(jogador02_digita_palavra_img, jogador02_digita_palavra)

        txt_orientacao = fonte_textos.render("DESCUBRA A PALAVRA:", True, (255,200,0))
        tela.blit(txt_orientacao, (70, 220))

        txt_orientacao = fonte_nivel.render("NÍVEL: "+str(nivel_jogo), True, (255,200,0))
        tela.blit(txt_orientacao, (470, 73))

        palavra_enigma = ''
        for item in estado_atual_enigma:
             palavra_enigma += f'{item} '

        tela.blit(forca_status_img, forca_status)

        txt_palavra_escondida = fonte_letras.render(palavra_enigma, True, (255,255,255))
        tela.blit(txt_palavra_escondida, (50, 250))

        txt_letras_digitadas = fonte_textos.render(letras_digitadas, True, (255,255,255))
        tela.blit(txt_letras_digitadas, (70, 400))

        if letra_ja_digitada:
            txt_alerta = fonte_textos.render("Essa letra já foi digitada", True, (255,200,0))
            tela.blit(txt_alerta, (70, 300))

        tela.blit(placar_img, placar)

        tela.blit(jogador01_img, jogador01)
        txt_placar_jogador01 = fonte_placar.render(str(pontos_jogador01), True, (255,255,255))
        tela.blit(txt_placar_jogador01, (440, 35))

        tela.blit(jogador02_img, jogador02)
        txt_placar_jogador02 = fonte_placar.render(str(pontos_jogador02), True, (255,255,255))
        tela.blit(txt_placar_jogador02, (550, 35))

        tela.blit(btn_home_img, btn_home)
        tela.blit(btn_reiniciar_img, btn_reiniciar)
        tela.blit(fade_img, fade)

    elif cena == "jogador_informa_palavra":
        trilha.set_volume(0.5)
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                exit()

            if event.type == pygame.MOUSEBUTTONDOWN:
                if btn_menu.collidepoint(event.pos):
                    click_menu()
                    fade_alpha = 255
                    erros = 0
                    acertos = 0

                    estado_atual_enigma = ["_"] * len(palavra_selecionada)
                    letras_digitadas = ''
                    cena = "menu"

            if event.type == pygame.MOUSEBUTTONDOWN:
                if btn_continuar.collidepoint(event.pos):
                    if text != "":
                        click_menu()
                        fade_alpha = 255
                        erros = 0
                        acertos = 0
                        palavra_selecionada = text
                        estado_atual_enigma = ["_"] * len(palavra_selecionada)
                        letras_digitadas = ''
                        lancar_ponto_jog01 = True
                        lancar_ponto_jog02 = True
                        qtd_ifens_na_palavra =0
                        cena = "jogo"

                    else:

                        texto_deve_ditar_palavra = "VOCÊ PRECISA DIGITAR UMA PALAVRA!"

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_BACKSPACE:
                    if len(text) > 0:

                        text = text[:-1]
                else:
                    text += event.unicode.upper()
                    texto_deve_ditar_palavra = ''

                img = font.render(text, True, (255, 200, 0))
                rect.size = img.get_size()
                cursor.topleft = rect.topright

        if fade_alpha > 0:
            fade_alpha -= 15
            fade_img.set_alpha(fade_alpha)

        tela.fill((40,10,50))
        tela.blit(fundo_img, fundo)

        tela.blit(btn_continuar_img, btn_continuar)
        tela.blit(btn_menu_img, btn_menu)

        tela.blit(placar_img, placar)
        if not jogador01_responde:
            tela.blit(jogador01_digita_palavra_img, jogador01_digita_palavra)
        elif jogador01_responde:
            tela.blit(jogador02_digita_palavra_img, jogador02_digita_palavra)

        tela.blit(jogador01_img, jogador01)
        txt_placar_jogador01 = fonte_placar.render(str(pontos_jogador01), True, (255,255,255))
        tela.blit(txt_placar_jogador01, (440, 35))

        tela.blit(jogador02_img, jogador02)
        txt_placar_jogador02 = fonte_placar.render(str(pontos_jogador02), True, (255,255,255))
        tela.blit(txt_placar_jogador02, (550, 35))

        txt_alerta_digite_palavra = fonte_textos.render(texto_deve_ditar_palavra, True, (255,200,0))
        tela.blit(txt_alerta_digite_palavra, (70, 250))

        txt_orientacao = fonte_textos.render("Digite a palavra:", True, (255,200,0))
        tela.blit(txt_orientacao, (70, 200))
        tela.blit(img, rect)
        if time.time() % 1 > 0.5:
            pygame.draw.rect(tela, (255, 0, 0), cursor)

        tela.blit(fade_img, fade)

    elif cena == "fim_jogo":

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

        if event.type == pygame.MOUSEBUTTONDOWN:
            if btn_menu.collidepoint(event.pos):
                click_menu()
                fade_alpha = 255
                limpar_variaveis()
                cena = "menu"

        if fade_alpha > 0:
            fade_alpha -= 15
            fade_img.set_alpha(fade_alpha)

        tela.fill((40,10,50))
        tela.blit(fundo_img, fundo)

        trilha.set_volume(0.2)

        if qtd_jogador == 1:
            if pontos_jogador01 == 10:
                msg_resultado_img = pygame.image.load("assets/img_ganhou.png")
                audio_venceu()

            elif pontos_jogador02 == 10:
                trilha.stop()
                audio_perdeu()
                msg_resultado_img = pygame.image.load("assets/img_perdeu.png")
        else:
            if pontos_jogador01 == 10:
                audio_venceu()
                msg_resultado_img = pygame.image.load("assets/img_ganhou.png")
                msg_indica_jogador_img = pygame.image.load("assets/img_indica_jogador01.png")

            elif pontos_jogador02 == 10:
                audio_venceu()
                msg_resultado_img = pygame.image.load("assets/img_ganhou.png")
                msg_indica_jogador_img = pygame.image.load("assets/img_indica_jogador02.png")

        tela.blit(msg_resultado_img, msg_resultado)
        tela.blit(msg_indica_jogador_img, msg_indica_jogador)
        tela.blit(btn_menu_img, btn_menu)
        tela.blit(fade_img, fade)

    elif cena == "fim_partida":
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                exit()

        if event.type == pygame.MOUSEBUTTONDOWN:
            if btn_menu.collidepoint(event.pos):
                audio_acertou.stop()
                click_menu()
                fade_alpha = 255
                limpar_variaveis()
                cena = "menu"

        if event.type == pygame.MOUSEBUTTONDOWN:
            if btn_proxima.collidepoint(event.pos):
                click_menu()
                audio_acertou.stop()
                audio_errou.stop()
                if qtd_jogador == 1:
                    fade_alpha = 255
                    limpar_variaveis()
                    cena = "jogo"
                else:
                    fade_alpha = 255
                    text = ''
                    img = font.render(text, True, (255, 200, 0))
                    rect.size = img.get_size()
                    cursor.topleft = rect.topright
                    jogador01_responde = not jogador01_responde
                    cena = "jogador_informa_palavra"
        if fade_alpha > 0:
            fade_alpha -= 15
            fade_img.set_alpha(fade_alpha)

        tela.fill((51,51,51))
        tela.blit(fundo_img, fundo)
        txt_palavra = fonte_textos.render("A PALAVRA É: "+palavra_selecionada, True, (255,255,255))
        tela.blit(txt_palavra, ((largura/2)-(txt_palavra.get_width()/2), 300))

        trilha.set_volume(0.2)

        if acertou_palavra:
            audio_acertou.play()
            audio_acertou.set_volume(0.5)
            msg_resultado_img = pygame.image.load("assets/img_acertou.png")
        else:
            audio_errou.play()
            audio_errou.set_volume(0.5)
            msg_resultado_img = pygame.image.load("assets/img_errou.png")

        tela.blit(msg_resultado_img, msg_resultado)

        if qtd_jogador == 2:
            if jogador01_responde:
                 msg_indica_jogador_img = pygame.image.load("assets/img_indica_jogador01.png")
            else:
                 msg_indica_jogador_img = pygame.image.load("assets/img_indica_jogador02.png")
            tela.blit(msg_indica_jogador_img, msg_indica_jogador)

        tela.blit(btn_menu_img, btn_menu)
        tela.blit(btn_proxima_img, btn_proxima)
        tela.blit(fade_img, fade)

    elif cena == "config":
        if qtd_jogador == 1:
            btn_jogador_vs_maquina_img = pygame.image.load("assets/btn_jogador_vs_maquina_selecionado.png")
            btn_jogador_vs_jogador_img = pygame.image.load("assets/btn_jogador_vs_jogador.png")

        else:
            btn_jogador_vs_maquina_img = pygame.image.load("assets/btn_jogador_vs_maquina.png")
            btn_jogador_vs_jogador_img = pygame.image.load("assets/btn_jogador_vs_jogador_selecionado.png")

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

        if event.type == pygame.MOUSEBUTTONDOWN:
            if btn_gravar.collidepoint(event.pos):
                click_menu()
                fade_alpha = 255
                limpar_variaveis()
                cena = "menu"

        if event.type == pygame.MOUSEBUTTONDOWN:
            if btn_jogador_vs_maquina.collidepoint(event.pos):
                click_menu()
                qtd_jogador = 1
                btn_jogador_vs_maquina_img = pygame.image.load("assets/btn_jogador_vs_maquina_selecionado.png")
                btn_jogador_vs_jogador_img = pygame.image.load("assets/btn_jogador_vs_jogador.png")

        if event.type == pygame.MOUSEBUTTONDOWN:
            if btn_jogador_vs_jogador.collidepoint(event.pos):
                click_menu()
                qtd_jogador = 2
                btn_jogador_vs_maquina_img = pygame.image.load("assets/btn_jogador_vs_maquina.png")
                btn_jogador_vs_jogador_img = pygame.image.load("assets/btn_jogador_vs_jogador_selecionado.png")
                jogador02_img = pygame.image.load("assets/jogador02.png")

        if fade_alpha > 0:
            fade_alpha -= 15
            fade_img.set_alpha(fade_alpha)

        tela.fill((0,0,0))

        tela.blit(fundo_img, fundo)

        txt_titulo_config = fonte_titulos.render("Configurações", True, (255,255,255))
        tela.blit(txt_titulo_config, ((largura/2)-(txt_titulo_config.get_width()/2), 40))

        txt_quant_jogadores = fonte_textos.render("Quantos jogadores?", True, (255,255,255))
        tela.blit(txt_quant_jogadores, (50, 100))

        tela.blit(btn_jogador_vs_maquina_img, btn_jogador_vs_maquina)
        tela.blit(btn_jogador_vs_jogador_img, btn_jogador_vs_jogador)

        tela.blit(btn_gravar_img, btn_gravar)
        tela.blit(fade_img, fade)

    elif cena == "info":

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

        if event.type == pygame.MOUSEBUTTONDOWN:
            if btn_menu.collidepoint(event.pos):
                click_menu()
                fade_alpha = 255
                limpar_variaveis()
                cena = "menu"

        if fade_alpha > 200:
            fade_alpha -= 10
            fade_img.set_alpha(fade_alpha)

        tela.fill((40,10,50))
        tela.blit(fundo_menu_img, fundo_menu)
        tela.blit(fade_img, fade)

        txt_palavra = fonte_textos.render("Desenvolvido por:", True, (255,255,255))
        tela.blit(txt_palavra, ((largura/2)-(txt_palavra.get_width()/2), 170))

        txt_palavra = fonte_textos.render("JOSÉ BRÍCIO NEGRÃO DA ROCHA", True, (255,255,255))
        tela.blit(txt_palavra, ((largura/2)-(txt_palavra.get_width()/2), 220))
        txt_palavra = fonte_info.render("Como requisito avaliativo da disciplina Logica de Programação," , True, (255,255,255))
        tela.blit(txt_palavra, ((largura/2)-(txt_palavra.get_width()/2), 250))
        txt_palavra = fonte_info.render("do curso de Pós-Graduação em Desenvolvimento de Sistemas com JAVA" , True, (255,255,255))
        tela.blit(txt_palavra, ((largura/2)-(txt_palavra.get_width()/2), 270))
        txt_palavra = fonte_info.render("da UNICESUMAR" , True, (255,255,255))
        tela.blit(txt_palavra, ((largura/2)-(txt_palavra.get_width()/2), 290))

        btn_menu = btn_menu_img.get_rect(center=[largura/2, (altura/2)+130])
        tela.blit(btn_menu_img, btn_menu)

    elif cena == "menu":
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                exit()

        if event.type == pygame.MOUSEBUTTONDOWN:
            if btn_iniciar.collidepoint(event.pos):
                click_menu()
                limpar_variaveis()
                pontos_jogador01 = 0
                pontos_jogador02 = 0
                palavras.palavas_selecionadas = []
                fade_alpha = 255
                if qtd_jogador == 1:
                    cena = "jogo"
                else:
                    cena = "jogador_informa_palavra"

        if event.type == pygame.MOUSEBUTTONDOWN:
            if btn_config.collidepoint(event.pos):
                click_menu()
                fade_alpha = 255
                cena = "config"

        if event.type == pygame.MOUSEBUTTONDOWN:
            if btn_info.collidepoint(event.pos):
                click_menu()
                fade_alpha = 255
                cena = "info"

        if fade_alpha > 0:
            fade_alpha -= 15
            fade_img.set_alpha(fade_alpha)

        tela.fill((0,0,0))
        tela.blit(fundo_menu_img, fundo_menu)
        tela.blit(btn_iniciar_img, btn_iniciar)
        tela.blit(btn_config_img, btn_config)
        tela.blit(btn_info_img, btn_info)
        tela.blit(fade_img, fade)

    fps.tick(25)
    pygame.display.flip()


################################################################################################
##  Script Info: Extarcts features from headline and Body for the entire Dataset
##  Author: Mohammed Habibllah Baig
##  Date : 11/22/2017
################################################################################################
import os
import re
import nltk
import numpy as np
from sklearn import feature_extraction
from tqdm import tqdm
from nltk.sentiment.vader import SentimentIntensityAnalyzer
from os.path import basename
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
from gensim import models
from gensim.models.phrases import Phraser
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.preprocessing import normalize
from nltk import word_tokenize, pos_tag, ne_chunk, sent_tokenize
from nltk.sentiment.vader import SentimentIntensityAnalyzer
from nltk.chunk import tree2conlltags
from nltk.stem import PorterStemmer

def clean(s):
    # Cleans a string: Lowercasing, trimming, removing non-alphanumeric

    return " ".join(re.findall(r'\w+', s, flags=re.UNICODE)).lower()

_wnl = nltk.WordNetLemmatizer()

def ExtractFeatures(feat_fn, headlines, bodies, feature_file):
    if not os.path.isfile(feature_file):
        feats = feat_fn(headlines, bodies)
        np.save(feature_file, feats)

    return np.load(feature_file)

def Lemmatization(w):
    return _wnl.lemmatize(w).lower()

def Tokenization(s):
    return [Lemmatization(t) for t in nltk.word_tokenize(s)]

def remove_stopwords(l):
    # Removes stopwords from a list of tokens
    return [w for w in l if w not in feature_extraction.text.ENGLISH_STOP_WORDS]

def Jaccard_Similarity(headlines, bodies):
    """ It calculates the degree of overlap between Headline and Body of news article"""
    X = []
    for i, (headline, body) in tqdm(enumerate(zip(headlines, bodies))):
        #clean_headline=clean(headline)
        #clean_body=clean(body)
        Tokenized_headline = Tokenization(headline)
        Tokenized_body = Tokenization(body)
        features = [
            len(set(Tokenized_headline).intersection(Tokenized_body)) / float(len(set(Tokenized_headline).union(Tokenized_body)))]
        X.append(features)
    return X

"""It calculates the polarity scores of headline and body using
Vader(Valence Aware Dictionary and Sentiment Reasoner) sentiment analyzer."""

def sentiment_feature(headlines, bodies):
    X=[]
    sent = SentimentIntensityAnalyzer()

    for i, (headline, body) in tqdm(enumerate(zip(headlines, bodies))):
        features = []
        headVader = sent.polarity_scores(headline)
        bodyVader = sent.polarity_scores(body)
        features.append(abs(headVader['pos']-bodyVader['pos']))
        features.append(abs(headVader['neg']-bodyVader['neg']))
        X.append(features)
    return X

def named_entity_feature(headlines, bodies):
    """ Retrieves a list of Named Entities from the Headline and Body.
    Returns a list containing the cosine similarity between the counts of the named entities """
    stemmer = PorterStemmer()
    def Extract_POS_tags(text):
        return pos_tag(word_tokenize(text))

    def filter_pos(named_tags, tag):
        return " ".join([stemmer.stem(name[0]) for name in named_tags if name[1].startswith(tag)])

    named_cosine = []
    tags = ["NN"]

    for i, (headline, body) in tqdm(enumerate(zip(headlines, bodies))):
        stance_cosine = []
        head = Extract_POS_tags(headline)
        body = Extract_POS_tags(body[:255])

        for tag in tags:
            head_f = filter_pos(head, tag)
            body_f = filter_pos(body, tag)

            if head_f and body_f:
                vect = TfidfVectorizer(min_df=1)
                tfidf = vect.fit_transform([head_f,body_f])
                cosine = (tfidf * tfidf.T).todense().tolist()
                if len(cosine) == 2:
                    stance_cosine.append(cosine[1][0])
                else:
                    stance_cosine.append(0)
            else:
                stance_cosine.append(0)
        named_cosine.append(stance_cosine)
    return named_cosine

def polarity_features(headlines, bodies):
    _refuting_words = [ 'fake','fraud','hoax','false','deny', 'denies','not','despite','nope','doubt',
    'doubts','bogus','debunk','pranks','retract'
    ]

    def check_polarity(text):
        tokens = Tokenization(text)
        return sum([t in _refuting_words for t in tokens]) % 2

    X = []
    for i, (headline, body) in tqdm(enumerate(zip(headlines, bodies))):
        clean_headline = clean(headline)
        clean_body = clean(body)
        features = []
        features.append(check_polarity(clean(headline)))
        features.append(check_polarity(clean(body)))
        X.append(features)
    return np.array(X)

def count_chargrams(features, text_headline, text_body, size):
    def chargrams(input, n):
        output = []
        for i in range(len(input) - n + 1):
            output.append(input[i:i + n])
        return output

    headline_words = [' '.join(x) for x in chargrams(" ".join(remove_stopwords(text_headline.split())), size)]
    match_count = 0
    match_early_count = 0
    match_first_count = 0
    for word in headline_words:
        if word in text_body:
            match_count += 1
        if word in text_body[:255]:
            match_early_count += 1
        if word in text_body[:100]:
            match_first_count += 1
    features.append(match_count)
    features.append(match_early_count)
    features.append(match_first_count)
    return features

def count_ngrams(features, text_headline, text_body, size):
    def ngrams(input, n):
        input = input.split(' ')
        output = []
        for i in range(len(input) - n + 1):
            output.append(input[i:i + n])
        return output

    headline_words = [' '.join(x) for x in ngrams(text_headline, size)]
    match_count = 0
    match_early_count = 0
    for word in headline_words:
        if word in text_body:
            match_count += 1
        if word in text_body[:255]:
            match_early_count += 1
    features.append(match_count)
    features.append(match_early_count)
    return features

def Misc_features(headlines, bodies):

    def count_matching_tokens(headline, body):
        # Count how many times a token in the title
        # appears in the body text.
        count = 0
        count_early = 0
        for headline_token in clean(headline).split(" "):
            if headline_token in clean(body):
                count += 1
            if headline_token in clean(body)[:255]:
                count_early += 1
        return [count, count_early]

    def count_matching_tokens_stops(headline, body):
        # Count how many times a token in the title
        # appears in the body text. Stopwords in the title
        # are ignored.
        count = 0
        count_early = 0
        for headline_token in remove_stopwords(clean(headline).split(" ")):
            if headline_token in clean(body):
                count += 1
                count_early += 1
        return [count, count_early]

    def count_grams(headline, body):
        # Count how many times an n-gram of the title
        # appears in the entire body, and intro paragraph

        clean_body = clean(body)
        clean_headline = clean(headline)
        features = []
        features = count_chargrams(features, clean_headline, clean_body, 2)
        features = count_chargrams(features, clean_headline, clean_body, 8)
        features = count_chargrams(features, clean_headline, clean_body, 4)
        features = count_chargrams(features, clean_headline, clean_body, 16)
        features = count_ngrams(features, clean_headline, clean_body, 2)
        features = count_ngrams(features, clean_headline, clean_body, 3)
        features = count_ngrams(features, clean_headline, clean_body, 4)
        features = count_ngrams(features, clean_headline, clean_body, 5)
        features = count_ngrams(features, clean_headline, clean_body, 6)
        return features

    X = []
    for i, (headline, body) in tqdm(enumerate(zip(headlines, bodies))):
        X.append(count_matching_tokens(headline, body)
             + count_matching_tokens_stops(headline, body)
             + count_grams(headline, body))

    return X

def BoW_feature( bodies,bag):
    X=[]
    for i, (headline, body) in tqdm(enumerate(zip( bodies))):
        features = np.zeros(len(bag))
        body_set=set(body)
        i=0
        for word in bag:
            if word in body_set:
                features[i]=1
            i=i+1
        X.append(features)
    return X


from tkinter import *

from tkinter import messagebox

root = Tk()
variable1 = StringVar(root)
variable2 = StringVar(root)

variable1.set("lang-code")
variable2.set("lang-code")

'''
VARIABLE KEY
'cipher' -> 'stores the morse translated form of the english string'
'decipher' -> 'stores the english translated form of the morse string'
'citext' -> 'stores morse code of a single character'
'i' -> 'keeps count of the spaces between morse characters'
'message' -> 'stores the string to be encoded or decoded'
'''

MORSE_CODE_DICT = { 'A':'.-', 'B':'-...',
					'C':'-.-.', 'D':'-..', 'E':'.',
					'F':'..-.', 'G':'--.', 'H':'....',
					'I':'..', 'J':'.---', 'K':'-.-',
					'L':'.-..', 'M':'--', 'N':'-.',
					'O':'---', 'P':'.--.', 'Q':'--.-',
					'R':'.-.', 'S':'...', 'T':'-',
					'U':'..-', 'V':'...-', 'W':'.--',
					'X':'-..-', 'Y':'-.--', 'Z':'--..',
					'1':'.----', '2':'..---', '3':'...--',
					'4':'....-', '5':'.....', '6':'-....',
					'7':'--...', '8':'---..', '9':'----.',
					'0':'-----', ', ':'--..--', '.':'.-.-.-',
					'?':'..--..', '/':'-..-.', '-':'-....-',
					'(':'-.--.', ')':'-.--.-'}

def clearAll() :

	language1_field.delete(1.0, END)
	language2_field.delete(1.0, END)

def convert() :

	message = language1_field.get("1.0", "end")[:-1]

	if variable1.get() == variable2.get() :

		messagebox.showerror("Can't Be same Language")
		return

	elif variable1.get() == "Eng" and variable2.get() == "Morse" :

		rslt = encrypt(message)

	elif variable1.get() == "Morse" and variable2.get() == "Eng" :

		rslt = decrypt(message)

	else :

		messagebox.showerror("please choose valid language code..")
		return

	language2_field.insert('end -1 chars', rslt)

def encrypt(message):
	cipher = ''
	for letter in message:
		if letter != ' ':

			cipher += MORSE_CODE_DICT[letter] + ' '
		else:
			cipher += ' '

	return cipher

def decrypt(message):
	message += ' '

	decipher = ''
	citext = ''
	for letter in message:

		if (letter != ' '):

			i = 0
			citext += letter
		else:
			i += 1
			if i == 2 :

				decipher += ' '
			else:
				decipher += list(MORSE_CODE_DICT.keys())[
							list(MORSE_CODE_DICT .values()).index(citext)]
				citext = ''

	return decipher

if __name__ == "__main__" :

	root.configure(background = 'light green')
	root.geometry("400x350")
	root.title("Translator")
	headlabel = Label(root, text = 'Welcome to Morse Code Translator',
							fg = 'black', bg = "red")

	label1 = Label(root, text = "One Language ",
				fg = 'black', bg = 'dark green')

	label2 = Label(root, text = "From Language",
				fg = 'black', bg = 'dark green')

	label3 = Label(root, text = "To Language ",
				fg = 'black', bg = 'dark green')

	label4 = Label(root, text = "Converted Language ",
				fg = 'black', bg = 'dark green')

	headlabel.grid(row = 0, column = 1)
	label1.grid(row = 1, column = 0)
	label2.grid(row = 2, column = 0)
	label3.grid(row = 3, column = 0)
	label4.grid(row = 5, column = 0)

	language1_field = Text(root, height = 5, width = 25,
									font = "lucida 13")
	language2_field = Text(root, height = 5, width = 25,
									font = "lucida 13")

	language1_field.grid(row = 1, column = 1, padx = 10)
	language2_field.grid(row = 5, column = 1, padx = 10)

	languageCode_list = ["Eng", "Morse"]

	FromLanguage_option = OptionMenu(root, variable1, *languageCode_list)
	ToLanguage_option = OptionMenu(root, variable2, *languageCode_list)

	FromLanguage_option.grid(row = 2, column = 1, ipadx = 10)
	ToLanguage_option.grid(row = 3, column = 1, ipadx = 10)

	button1 = Button(root, text = "Convert", bg = "red", fg = "black",
								command = convert)

	button1.grid(row = 4, column = 1)

	button2 = Button(root, text = "Clear", bg = "red",
					fg = "black", command = clearAll)

	button2.grid(row = 6, column = 1)

	root.mainloop()


# coding: utf-8
import console
import sys
from markdown2 import markdown
import ui
import requests

TEMPLATE = '''
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Preview</title>
<style type="text/css">
body {
	font-family: helvetica;
	font-size: 15px;
	margin: 10px;
}
</style>
</head>
<body>{{CONTENT}}</body>
</html>
'''

def main():

	search_word = console.input_alert(u'想查哪个字的编码？')
	if not search_word:
		print('No text input found.')
		sys.exit(0)

	url = "https://www.iamwawa.cn/home/wubi/ajax"

	headers = {
		'Origin': 'https://www.iamwawa.cn',
		'Referer': 'https://www.iamwawa.cn/wubi.html',
		'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36',
		}

	payload = {"hanzi": search_word}

	response = requests.post(url,headers=headers, data=payload)

	res_dict = {}
	if response.status_code == 200:
		data = response.json()

		if data['status'] == 1:
			res_dict = data['data'][0]

		else:
			print(response.json())
	else:
		print('请求异常')
		print(response.json())
		sys.exit(1)

	text = "# {}\n - 98简码: {}\n - 98编码: {}\n - 拼音: {}\n\n![](https://iamwawa.cn/Data/wubi/{}.png)".format(search_word,res_dict["c98j"],res_dict["c98"],res_dict["py"],search_word)
	converted = markdown(text)
	html = TEMPLATE.replace('{{CONTENT}}', converted)
	webview = ui.WebView(name='98五笔编码查询')
	webview.load_html(html)
	webview.present()

if __name__ == '__main__':
	main()


import pydantic
import pytest

from huma_signals.clients.polygon_client import polygon_client
from tests.helpers import vcr_helpers

_FIXTURE_BASE_PATH = "/clients/polygon_client"

class Settings(pydantic.BaseSettings):
    class Config:
        case_sensitive = False

    polygonscan_base_url: str
    polygonscan_api_key: str

settings = Settings()

def describe_PolygonClient() -> None:
    @pytest.fixture
    def client() -> polygon_client.PolygonClient:
        return polygon_client.PolygonClient(
            polygonscan_base_url=settings.polygonscan_base_url,
            polygonscan_api_key=settings.polygonscan_api_key,
        )

    def describe_get_transactions() -> None:
        async def it_returns_the_transactions(
            client: polygon_client.PolygonClient, real_polygon_address: str
        ) -> None:
            with vcr_helpers.use_cassette(
                fixture_file_path=f"{_FIXTURE_BASE_PATH}/get_transactions.yml"
            ):
                transactions = await client.get_transactions(real_polygon_address)
                assert len(transactions) > 1400

        def when_the_address_has_no_records() -> None:
            async def it_works_properly(client: polygon_client.PolygonClient) -> None:
                with vcr_helpers.use_cassette(
                    fixture_file_path=f"{_FIXTURE_BASE_PATH}/get_transactions_no_records.yml"
                ):
                    transactions = await client.get_transactions("0x1234")
                    assert len(transactions) == 0


#!/usr/bin/env python3
"""
Grab an image off the internet at regular intervals.
"""
import argparse
import datetime
import json
import logging
import threading
from io import BytesIO
import time
import timeit
import requests
from PIL import Image

logging.basicConfig(level=logging.INFO,
                    format='(%(threadName)-10s) %(message)s')

class Webcam(object):
    """
    Class to download webcam image from an URL
    """
    SAVED = 0
    TOO_DARK = 1
    SAME = 3
    NIGHT = 4

    def __init__(self):
        """
        Constructor
        """
        self.image = None

    def grab(self, last_filename, filename, avg=0, url=None):
        """
        Helper method that grabs the image and check its light level
        and compares it to the last image.

        :param last_filename: File name of the last image
        :param filename: File name to save the new image to
        :param avg: Avarage light level floor
        :param url: Url of the webcam preview image.
        :return: Webcam.SAVED, Webcam.TOO_DARK, Webcam.SAME, and Webcam.NIGHT
        """
        self.image = None
        self.grab_image(url)

        logging.debug("Last image:\t\t%s", last_filename)

        if last_filename is None:
            # No last image
            if self.image_average() >= avg:
                # Light is okay, save
                logging.info("Saving:\t\t\t%s", filename)
                self.image.save(filename, "PNG")
                return Webcam.SAVED

            return Webcam.TOO_DARK

        logging.debug(self.file_isdiff(last_filename))

        if not self.file_isdiff(last_filename):
            logging.warning("Same as last image")
            return Webcam.SAME

        if self.image_average() >= avg:
            logging.info("Saving:\t\t\t%s", filename)
            self.image.save(filename, "PNG")
            return Webcam.SAVED

        return Webcam.TOO_DARK

    def grab_image(self, url):
        """
        Download an image from an URL.

        :param url: URL of the image
        """
        if url is None:
            logging.error("Error: No webcam URL")
            return

        response = requests.get(url)
        self.image = Image.open(BytesIO(response.content))

    def file_isdiff(self, filename):
        """
        Compare this image to a file.

        :param filename: File name of the image.
        :return: True if different.
        """
        diff = 0
        if self.image is None:
            logging.error("Error: No image data")
            return True

        fimage = Image.open(filename)

        spixels = list(self.image.getdata())
        fpixels = list(fimage.getdata())

        for pixel in range(0, len(spixels)):
            if spixels[pixel] != fpixels[pixel]:
                diff += 1

        logging.debug("Number of different pixels %d", diff)

        if diff < 10:
            return False

        return True

    def image_average(self):
        """
        Calculate the avrage B/W light level.

        :return: the avarage B/W level of the picture in percent
        """
        if self.image is None:
            logging.error("Error: No image data")
            return 100
        pixels = list(self.image.getdata())

        avg = 0
        npixels = 0

        for pixel in pixels:
            avg += (pixel[0] + pixel[1] + pixel[2]) / 3
            npixels += 1

        avg /= npixels
        percent = avg / 256 * 100
        logging.info("Light level:\t\t{:3.2f}%".format(percent))
        return percent

class Daytime(object):
    """
    Class that handles daytime information.

    Uses https://sunrise-sunset.org/ to get the daytime data.
    """

    def __init__(self, lat, lon):
        """
        Constructor.

        :param lat: Latitude of the camera location
        :param lon: Longetiude of the camera location
        """
        self.lat = lat
        self.long = lon
        self.up_time = None
        self.down_time = None

    def update(self):
        """
        Update daylight times from the remote API.
        """
        response = requests.get('https://api.sunrise-sunset.org/json?' +
                                'lat={}&lng={}&date=today'.format(self.lat,
                                                                  self.long))
        if response.ok:
            json_resp = response.text
            daytime = json.loads(json_resp)

            def get_utc(utc):
                """
                Add current date to 12 hour UTC time.

                :param utc: 12 hour UTC time
                :return: datetime.datetime object with UTC time + current date.
                """
                if utc[0] != '0' and utc[1] == ':':
                    utc = "0{}".format(utc)
                date = datetime.datetime.now().strftime("%Y-%m-%d ")
                utc_time = datetime.datetime.strptime(
                    date + utc, '%Y-%m-%d %I:%M:%S %p')
                return utc_time

            self.up_time = get_utc(
                daytime['results']['civil_twilight_begin'])
            self.down_time = get_utc(
                daytime['results']['civil_twilight_end'])
            logging.info("Daylight begins:\t\t%s",
                         self.up_time.strftime('%Y-%m-%d %H:%M:%S UTC'))
            logging.info("Daylight ends:\t\t%s",
                         self.down_time.strftime('%Y-%m-%d %H:%M:%S UTC'))

    def check_daylight(self):
        """
        Check if there is daylight.

        :return: True if in daylight period, False otherwise
        """
        if self.up_time is None or self.down_time is None:
            logging.error("Error: No daytime information")
            return False

        current_time = datetime.datetime.utcnow()
        if current_time > self.up_time and current_time < self.down_time:
            return True

        return False

    def get(self):
        """
        Get daylight times.

        :return: Tuple of up time and down time
        """
        return (self.up_time, self.down_time)

TIMERS = {}

def named_timer(name, interval, function, *args, **kwargs):
    """Factory function to create named Timer objects.

      Timers call a function after a specified number of seconds:

          t = Timer('Name', 30.0, function)
          t.start()
          t.cancel()  # stop the timer's action if it's still waiting
    """
    timer = threading.Timer(interval, function, *args, **kwargs)
    timer.name = name
    TIMERS[name] = {}
    TIMERS[name]['start'] = datetime.datetime.now()
    TIMERS[name]['interval'] = interval
    return timer

def start(interval, url, target_dir, light_percent=0, daylight=[]):
    logging.info("Interval:\t\t\t%d", interval)
    logging.info("URL:\t\t\t%s", url)
    logging.info("Directory:\t\t\t%s", target_dir)
    logging.info("Light level threshold:\t%d%%", light_percent)

    if len(daylight) == 2:
        daytime = Daytime(daylight[0], daylight[1])

        def daytime_worker():
            """
            Worker to update daytime and restart the thread waiting
            """
            logging.debug("Starting new daytime worker")
            daytime_wait = 21600
            try:
                daytime.update()
            except:
                logging.error("Exception during daytime update")
                daytime_wait = 120
            finally:
                daytime_thread = named_timer("DaytimeThread",
                                             daytime_wait,
                                             daytime_worker)
                daytime_thread.start()

        daytime_worker()
    else:
        daytime = None

    webcam = Webcam()

    def webcam_worker(last_filename, skipped, cur_interval):
        """
        Worker to grab an image and restart the thread waiting
        """
        start_time = timeit.default_timer()
        logging.debug("Starting new webcam worker")
        try:
            filename = "{}/{}.png".format(
                target_dir,
                datetime.datetime.utcnow().strftime('%Y-%m-%d_%H-%M-%S_UTC'))
            grabbed = -1
            if daytime is None:
                # If we do not care about daytime, just grab the image
                grabbed = webcam.grab(last_filename, filename,
                                      light_percent, url)
            else:
                if daytime.check_daylight():
                    grabbed = webcam.grab(
                        last_filename, filename, light_percent, url)
                else:
                    daylight = daytime.get()
                    cur_interval = (
                        daylight[0] - datetime.datetime.utcnow()).total_seconds()
                    if cur_interval > 3600 or cur_interval < 0:
                        cur_interval = 3600
                    logging.info("Waiting for day light")

            if grabbed == Webcam.SAVED:
                last_filename = filename
                skipped = 0
                cur_interval = interval
            elif grabbed == Webcam.TOO_DARK:
                skipped += 1
                logging.info("Skipped...%d", skipped)
                if skipped >= 5:
                    if skipped == 5:
                        logging.info("5 images skipped, increasing interval")
                    cur_interval *= 2
                    if cur_interval > 1500:
                        logging.info("Resetting interval")
                        cur_interval = interval
            elif grabbed == Webcam.SAME:
                skipped += 1
                logging.info("Skipped...%d", skipped)

                if skipped >= 5:
                    if skipped == 5:
                        logging.info("5 images skipped, increasing interval")
                    cur_interval *= 2
                    if cur_interval > 1500:
                        logging.info("Resetting interval")
                        cur_interval = interval
                else:
                    cur_interval = 5

            logging.info("Waiting {:.0f} seconds".format(cur_interval))
        except:
            logging.error("Exception during webcam grab")
        finally:
            cur_interval -= timeit.default_timer() - start_time

            webcam_thread = named_timer("WebcamThread",
                                        cur_interval,
                                        webcam_worker,
                                        args=(last_filename, skipped, cur_interval))
            webcam_thread.start()

    webcam_worker(None, 0, interval)

    logging.info("All threads running, press CTRL-C to quit")
    seconds = 0
    main_thread = threading.currentThread()
    try:
        while True:
            time.sleep(1)
            seconds += 1
            if seconds > 900:
                seconds = 0
                for thread in threading.enumerate():
                    if thread is not main_thread:
                        elapsed = (datetime.datetime.now() -
                                   TIMERS[thread.name]['start']).total_seconds()
                        logging.info("Thread: %s", thread.name)
                        logging.info("\tWaited:\t\t%d seconds", elapsed)
                        logging.info("\tWaiting:\t%d seconds",
                                     TIMERS[thread.name]['interval'] - elapsed)
    except KeyboardInterrupt:
        logging.info("Stopping...")

    for thread in threading.enumerate():
        if thread is not main_thread:
            logging.debug('Stopping %s', thread.getName())
            thread.cancel()

def main():
    """
    Main entry point
    """
    parser = argparse.ArgumentParser()
    parser.add_argument('interval', type=int,
                        help='Interval between grabs, in secends', default=60)
    parser.add_argument('url', type=str, help='URL of the image')
    parser.add_argument('target_dir', type=str, help='Target directory')
    parser.add_argument('-l, --light', type=int, dest='light_percent',
                        help="Image are discarded below this B/W light level " +
                        "in percent", default=0)
    parser.add_argument('-d, --daylight', nargs=2, default=[], dest='daylight',
                        help='Longitude and latitude to only grab during ' +
                        'astronomical daylight hours')
    args = parser.parse_args()

    start(args.interval,
          args.url,
          args.target_dir,
          args.light_percent,
          args.daylight)

if __name__ == "__main__":
    main()


import uproot
import matplotlib.pyplot as plt
import numpy as np
import functions as fnc
import pandas as pd

from scipy import signal
from scipy.fft import rfft, rfftfreq

################ DESCRIPTION
# OBSOLETE CODE FROM START OF PROJECT
# Only kept due to usefulness of some of the operations within it.
################

# PMTsignals/Run203-PMT107.root
# PMTsignals/Run203-PMT78.root
# PMTsignals/Run103-noise-PMT78.root
# PMTsignals/Run103-noise-PMT107.root

#file = uproot.open("PMTsignals/Run203-PMT107.root")
#print(file.keys())

#print(file["Tree"].values())
#print(file["Tree"].keys())

# Open the data, apply to variable
file = "PMTsignals/Run203-PMT78.root"

tree = uproot.open(file)["Tree"]
branches = tree.arrays()
print(branches['ADC'])

# 10000 events
data = branches['ADC'][10]

time = []
# Creating list for sample times that are 2ns intervals, 150 samples
for i in range(150):
    time.append(i*2)

for i in range(100):
    datarepeated = branches['ADC'][i]
    plt.plot(time,datarepeated)
    plt.xlabel("Sample Time (ns)")
    plt.ylabel("ADC Value")
    plt.title(str(file) + " event " + str(i))
    plt.show()

# So we have in the file:

# -["Tree"]
#   -['ADC']
#     -[1]
#     -[2]
#     -[...]
#     -[10000]

# Choose rolling average?
join = input("Use running mean data? [Y/N]")
if join.lower() == 'y':
    # Testing rolling averages with pandas
    df = pd.DataFrame({'A': data})
    # window of 3 for our rolling average
    df_rolling = df.rolling(5,min_periods=1).mean()
    print(df_rolling)
    data = df_rolling['A'].tolist()
elif join.lower() == 'n':
    print("Continuing without running mean data...")

# ACHTUNG, THIS CODE IS NOW OBSOLETE AND WILL MOST LIKELY NOT FUNCTION
# Line of best fit, to see modulation in baseline
datanew = data['ADC']
yline, pfit, stats, rms = fnc.linfit(time,datanew,1)
c, m = pfit

# Plot line of best fit over data
plt.plot(time,data,color='black',markersize=2)
plt.plot(time,yline,color='red',linewidth=3)
plt.xlabel("Sample Time (ns)")
plt.ylabel("ADC Value")
plt.title("Trendline of " + str(file))
plt.show()

# Now, remove baseline (and possibly also linear modulation, if it effects results significantly)
bslndata = data - c

# Plot removed baseline
plt.plot(time,bslndata,color='black',markersize=2)
plt.xlabel("Sample Time (ns)")
plt.ylabel("ADC Value")
plt.title("Trendline of " + str(file) + " with baseline reduction")
plt.show()

# FFT experimentation
# will alter sample spacing if it causes issues

#sampling rate is 500MHz (2ns sampling time over 300ns)

yf = rfft(bslndata)
xf = rfftfreq(len(bslndata),1/500)

plt.plot(xf,yf)
plt.title("Rough Fourier Transform of " + str(file))
plt.xlabel("Frequency (MHz)")
plt.ylabel("Amplitude")
plt.show()

# looking at butterworth filter, removing everything above 220MHz

sos = signal.butter(10,200,'lp',fs=500,output='sos')
filtereddata = signal.sosfilt(sos,bslndata)

plt.plot(time,filtereddata)
plt.title("Butterworth Filtered Signal of " + str(file))
plt.xlabel("Sample Time (ns)")
plt.ylabel("ADC Value")
plt.show()

# Fourier Transform
yfbut = rfft(filtereddata)

plt.plot(xf,yfbut)
plt.title("Butterworth Fourier Transform of " + str(file))
plt.xlabel("Frequency (MHz)")
plt.ylabel("Amplitude")
plt.show()


import paddle
import paddle.nn as nn

class PointNet_Basic_Clas(nn.Layer):
    def __init__(self, num_classes=10, max_points=1024):
        super(PointNet_Basic_Clas, self).__init__()
        self.mlp_1 = nn.Sequential(
            nn.Conv1D(3, 64, 1),
            nn.BatchNorm(64),
            nn.ReLU(),
            nn.Conv1D(64, 64, 1),
            nn.BatchNorm(64),
            nn.ReLU(),
        )
        self.mlp_2 = nn.Sequential(
            nn.Conv1D(64, 64, 1),
            nn.BatchNorm(64),
            nn.ReLU(),
            nn.Conv1D(64, 128, 1),
            nn.BatchNorm(128),
            nn.ReLU(),
            nn.Conv1D(128, max_points, 1),
            nn.BatchNorm(max_points),
            nn.ReLU(),
        )
        self.fc = self.fc = nn.Sequential(
            nn.Linear(1024, 512),
            nn.ReLU(),
            nn.Linear(512, 256),
            nn.ReLU(),
            nn.Dropout(p=0.7),
            nn.Linear(256, num_classes)
        )
    def forward(self, inputs):
        """
            Input:
                inputs: input points data, [B, 3, N]
            Return:
                x: predicts, [B, num_classes]
        """
        x = paddle.to_tensor(inputs)
        x = self.mlp_1(x)
        x = self.mlp_2(x)
        x = paddle.max(x, axis=2)
        x = self.fc(x)

        return x

if __name__ == '__main__':
    model = PointNet_Basic_Clas()
    paddle.summary(model, (64, 3, 1024))


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Jul 15 15:17:41 2022

@author: archer
"""

import os
from datetime import datetime
import numpy as np
from scipy.linalg import sqrtm, qr, norm
from qiskit.extensions import UnitaryGate
from qiskit.quantum_info import Operator
from qiskit.opflow.list_ops import SummedOp

"""
How to apply a unitary gate

unitary = UnitaryGate(matrix, label="U")
circuit.append(unitary, register)

"""

class LinearDecompositionOfUnitaries:
    """Decomposes a matrix A with spectral_norm(A) <=1 to
    a sum of unitary matrices. Stores the appropriate values."""

    def __init__(self, matrix):
        if type(matrix)== np.ndarray:
            self.from_matrix(matrix)
        else:
            self.from_summed_op(matrix)
        self.num_unitaries = len(self.gates)
        self.decomposition = np.array(self.matrices)

    def from_summed_op(self, summed_op):
        self.matrix = summed_op.to_matrix()
        self.paulis = summed_op.to_pauli_op()
        try:
            _ = iter(self.paulis)
        except TypeError as te:
            self.paulis = SummedOp([self.paulis, 0*self.paulis])
        self.coeffs = np.array([pauli.coeff for pauli in self.paulis])
        self.coeffs = self.coeffs/norm(self.coeffs)/10
        self.gates = [pauli.to_circuit().to_gate() for pauli in self.paulis]
        self.matrices = [pauli.to_matrix() for pauli in self.paulis]
        self.matrix_norm = norm(self.matrix)
        self.matrix_normalized = self.matrix/self.matrix_norm

    def from_matrix(self, matrix):
        self.matrix = matrix
        self.matrix_norm = norm(self.matrix)
        self.matrix_normalized = self.matrix/self.matrix_norm
        matrices, coeffs = linear_decomposition_of_unitaries(self.matrix_normalized)
        self.matrices = matrices
        self.coeffs = np.array(coeffs)
        self.gates = [UnitaryGate(matrix, label=f'A_{i}')
                      for i, matrix in enumerate(matrices)]

    def valid_decomposition(self):
        unitary_sum = np.sum(self.coeffs[:, None, None] * self.decomposition, axis=0)
        if np.allclose(unitary_sum, self.matrix_normalized):
            return True
        else:
            return False

def unitary_from_hermitian(hermitian: np.ndarray, tol=1e-8):
    """ Decompose a real symmetric matrix to a sum of
    two unitary operators
    """

    identity = np.eye(N=hermitian.shape[0], dtype=np.complex128)

    matrix = identity - hermitian @ hermitian
    sqrt_mat = 1j*sqrtm(matrix)
    F1 = hermitian + sqrt_mat
    F2 = hermitian - sqrt_mat
    return F1, F2

def linear_decomposition_of_unitaries(array: np.ndarray):
    """ Decompose an array with det(array)<=1
    into a linear combination of unitaries

    :Input: ndarray with spectral_norm(array)<=1
    :Returns: a list of unitary arrays
        [F1, F2, F3, F4]

    A = B + iC

    B = 1/2 (F1 + F2), unitary
    C = 1/2 (F3 + F4), unitary

    A = 1/2 (F1 + F2 + iF3 + iF4)

    """
    array = array.astype(np.complex128)
    is_hermitian = np.allclose(array, array.conj().T)
    if is_hermitian:
        F1, F2 = unitary_from_hermitian(array)
        return (F1, F2), (.5, .5)

    else:
        symmetric_part = 1/2*(array + array.conj().T)
        antisymmetric_part = -1j/2*(array - array.conj().T)

        F1, F2 = unitary_from_hermitian(symmetric_part)
        F3, F4 = unitary_from_hermitian(antisymmetric_part)

        return (F1, F2, 1j*F3, 1j*F4), (.5, .5, .5, .5)

def unitary_from_column_vector(coeffs: np.ndarray, *args, **kwargs):
    """Constructs a unitary operator taking the zero state |0>
    to the state with coeffs as amplitudes, using QR decomposition
    """
    k = coeffs.shape[0]

    random_array = np.vstack([coeffs.ravel(), np.random.rand(k-1, k)])
    unitary, _ = qr(random_array.T)
    is_nonzero = unitary[:, 0].nonzero()[0][0]
    if unitary[is_nonzero, 0] * coeffs[is_nonzero] < 0:
        # assert same sign for operator and coeffs
        unitary *= -1
    return UnitaryGate(unitary, *args, **kwargs)

def states2qubits(num_states: int):
    if num_states==1:
        return 1
    return int(np.ceil(np.log2(num_states) ))

def adjoint(matrix: np.ndarray):

    return matrix.conj().T

def normalized(matrix: np.ndarray, return_norm=False):
    matrix_norm = norm(matrix, ord=2)
    return matrix/matrix_norm

def print_time(t, msg=''):
    print("# " + msg + f" Elapsed Time: {t:.2f}s")

class FileLogger:

    def __init__(self, filenames, directory='output', dateit=True):

        self.filenames = filenames
        self.dir = directory

        if dateit:
            directory += datetime.today().strftime("%Y%m%d_%H%M")

        try:
            os.makedirs(directory)
        except FileExistsError:
            print(f'{directory} already exists')

        self.directory = directory
        self.paths = [os.path.join(directory, name) for name in filenames]

    def save(self, data_list):
        if len(data_list) != len(self.filenames):
            raise ValueError(
                'Number of inputs must match number of initial filenames')

        for name, array in zip(self.paths, data_list):
            if array is not None:
                with open(name, 'a') as f:
                    array = np.atleast_2d(np.array(array))
                    if array.ndim > 2:
                        dims = array.shape
                        array = array.reshape((-1, dims[1]))
                    np.savetxt(f, array)


class Vertex:
    def __init__(self, coord):
        self.coord = coord
        self.edges = set()  # references to edges which attatch. Added upon edge creation
        self.deleted = False
        self.atom_name = "C"

    @property
    def secondary_verteces(self):  # returns set of secondary (one edge away verteces)
        secondary_verteces = set()
        for edge in self.edges:
            for vertex in edge.verteces:
                secondary_verteces.add(vertex)
        try:
            secondary_verteces.remove(self)
        except:
            pass
        return secondary_verteces
    @property
    def trimers(self):
        trimers = set()
        for edge in self.edges:
            for trimer in edge.trimers:
                trimers.add(trimer)
        return trimers

    def delete(self):
        self.deleted = True


import csv, string, sys, datetime, collections
#import #_datetime,
import string
import os

__author__ = 'Zhenxin Lei'

class StockMinData:
    ticker='JPM'
    timeStamp=[]
    closePrice=0
    highPrice=0
    lowPrice=0
    openPrice=0
    volume=0
    stockData = dict()

    # file setup for temp
    fileType='.csv'
    filePath='E:/University/Trading/Data/'
    os.path.dirname(__file__)
    #fileTimPeriod='20141006-20141017'
    #

    def __init__(self,ticker,fileTimPeriod):
        self.ticker=ticker
        self.fileTimPeriod=fileTimPeriod
        self.readMinData()

    def readMinData(self):
        script_dir = os.path.dirname(__file__) #<-- absolute dir the script is in
        rel_path = "../../com/resource/"
        abs_file_path = os.path.join(script_dir,rel_path)
        csvFile=open(abs_file_path +self.ticker+' '+self.fileTimPeriod+self.fileType)
        #csvFile=open(self.filePath+self.ticker+' '+self.fileTimPeriod+self.fileType)
        reader =csv.reader(csvFile, delimiter=',')
        for row in reader:
           # self.stockData.update(row[1]: row[2:])
            self.timeStamp.append(int(row[0]))
            #self.stockData.update({row[0]:row[1:]})
            priceList=[]
            for i in row[1:]:
               priceList.append(float(i))
            self.stockData.update({int(row[0]):priceList})
        return self.stockData

    # duration unit is second, 1min=60s
    def historicalHighAndLow(self,duration):
        high=dict()
        low=dict()
        startTime=self.timeStamp[0]

        localMax=float(self.stockData[startTime][0])
        localMin=float(self.stockData[startTime][0])
        startDurationTime=0

        for i in self.timeStamp:
            if (i>(startTime+duration)):
                startDurationTime=i
                break

        offset=self.timeStamp.index(startDurationTime)-self.timeStamp.index(startTime)

        for endTimeStamp in self.timeStamp[self.timeStamp.index(startDurationTime):]:
            startTimeStamp= self.timeStamp[self.timeStamp.index(endTimeStamp)-offset]
            localMax,localMin=self.findMaxAndMin(startTimeStamp,endTimeStamp)
            high.update({endTimeStamp:localMax})
            low.update({endTimeStamp:localMin})

        # for i in self.timeStamp:
        #     print(
        #     datetime.datetime.fromtimestamp(
        #         i
        #         ).strftime('%Y-%m-%d %H:%M:%S')
        #     )
        return (high,low)

    def findMaxAndMin(self,startTimeStamp,endTimeStamp):
        _localMax=float(self.stockData[startTimeStamp][0])
        _localMin=float(self.stockData[startTimeStamp][0])

        startIndex=self.timeStamp.index(startTimeStamp)
        endIndex=self.timeStamp.index(endTimeStamp)
        for i in self.timeStamp[startIndex:endIndex+1]:
            if (float(self.stockData[i][0])>=float(_localMax)):
                _localMax=float(self.stockData[i][0])
            if (float(self.stockData[i][0])<=float(_localMin)):
                _localMin=float(self.stockData[i][0])
        return (_localMax, _localMin)

#print(StockMinData('JPM','20141006-20141017').historicalHighAndLow(1500))