# -*- coding: utf-8 -*-
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
from tkinter import font
from dataclasses import dataclass
import openpyxl
import random

@dataclass
class config:
    # エクセルファイルのパスとシート名を指定
    file_name =   'FE単語意味頑張るマン.xlsx'
    wb = openpyxl.load_workbook(file_name)
    ws = wb.worksheets[0]
    titlefont=("メイリオ","64")
    checkbtn_font=("メイリオ","20")
    message_font= ("メイリオ","12")
    default_button_width = 20
    default_button_padding = 8
    chapter_1_text = "第一章　コンピュータの構成要素"
    chapter_2_text = "第二章　ソフトウェアとマルチメディア"
    chapter_3_text = "第三章　基礎理論"
    chapter_4_text = "第四章　アルゴリズムとプログラミング"
    chapter_5_text = "第五章　システム構成要素"
    chapter_6_text = "第六章　データベース技術"
    chapter_7_text = "第七章　ネットワーク技術"
    chapter_8_text = "第八章　情報セキュリティ"
    chapter_9_text = "第九章　システム開発技術"
    chapter_10_text = "第十章　マネジメント系"
    chapter_11_text = "第十一章　ストラテジ系"
    chapter_list = [    "第一章　コンピュータの構成要素",    "第二章　ソフトウェアとマルチメディア",    "第三章　基礎理論",    "第四章　アルゴリズムとプログラミング",    "第五章　システム構成要素",    "第六章　データベース技術",    "第七章　ネットワーク技術",    "第八章　情報セキュリティ",    "第九章　システム開発技術",    "第十章　マネジメント系",    "第十一章　ストラテジ系"]

class Application_index(tk.Frame):
    def __init__(self, root=None):
        super().__init__(root, width=1344, height=756, borderwidth=1, relief='solid')
        self.root = root
        self.pack(anchor='center',expand=1)
        self.pack_propagate(0)
        self.create_widgets()
        root.bind("q", lambda event: self.change_quest_setting() if self.quest_setting_btn.winfo_ismapped() else None)
        root.bind("w", lambda event: self.change_grades() if self.grades_btn.winfo_ismapped() else None)
        root.bind("e", lambda event: self.change_data() if self.data_btn.winfo_ismapped() else None)
        root.bind("c", lambda event: self.root.destroy() if self.return_btn.winfo_ismapped() else None)

    def create_widgets(self):
        style = ttk.Style()
        style.configure("default.TButton", font=("メイリオ", 16))

        # タイトルラベル
        label = tk.Label(self)
        label['text'] = 'FE単語意味頑張るマン'
        label['font'] = config.titlefont
        label.pack()

        # 閉じるボタン
        self.quit_btn = ttk.Button(self)
        self.quit_btn['text'] = '終了する'
        self.quit_btn['style'] = "default.TButton"
        self.quit_btn['width'] = config.default_button_width
        self.quit_btn['padding'] = config.default_button_padding
        self.quit_btn['command'] = self.root.destroy
        self.quit_btn.pack(side='bottom',anchor='sw')

        # 問題を解くボタン
        self.quest_setting_btn = ttk.Button(self)
        self.quest_setting_btn['text'] = '問題を解く(q)'
        self.quest_setting_btn['style'] = "default.TButton"
        self.quest_setting_btn['width'] = config.default_button_width
        self.quest_setting_btn['padding'] = config.default_button_padding
        self.quest_setting_btn['command'] = self.change_quest_setting
        self.quest_setting_btn.bind('<Return>', self.change_quest_setting)
        self.quest_setting_btn.pack()

        # 成績を見るボタン
        self.grades_btn = ttk.Button(self)
        self.grades_btn['text'] = '成績を見る(w)'
        self.grades_btn['style'] = "default.TButton"
        self.grades_btn['width'] = config.default_button_width
        self.grades_btn['padding'] = config.default_button_padding
        self.grades_btn['command'] = self.change_grades
        self.grades_btn.bind('<Return>', self.change_grades)
        self.grades_btn.pack()

        # データを変更するボタン
        self.data_btn = ttk.Button(self)
        self.data_btn['text'] = '成績を見る(e)'
        self.data_btn['style'] = "default.TButton"
        self.data_btn['width'] = config.default_button_width
        self.data_btn['padding'] = config.default_button_padding
        self.data_btn['command'] = self.change_data
        self.data_btn.bind('<Return>', self.change_data)
        self.data_btn.pack()

    def change_quest_setting(self,event=None):
        # 現在のフレームを非表示にする
        self.pack_forget()
        # 新しいフレームを作成して表示する
        app = Application_quest_setting(self.root)
        app.pack()

    def change_grades(self,event=None):
        # 現在のフレームを非表示にする
        self.pack_forget()
        # 新しいフレームを作成して表示する
        app = Application_grades(self.root)
        app.pack()

    def change_data(self,event=None):
        # 現在のフレームを非表示にする
        self.pack_forget()
        # 新しいフレームを作成して表示する
        app = Application_data(self.root)
        app.pack()

class Application_quest_setting(tk.Frame):
    def __init__(self, root=None):
        super().__init__(root, width=1344, height=756, borderwidth=1, relief='solid')
        self.root = root
        self.pack(anchor='center',expand=1)
        self.pack_propagate(0)
        self.create_widgets()
        self.quest_mode = 0
        root.bind("m", lambda event: self.change_index() if self.return_btn.winfo_ismapped() else None)
        root.bind("q", lambda event: self.yougo_to_imi_btn_click() if self.yougo_to_imi_btn.winfo_ismapped() else None)
        root.bind("w", lambda event: self.imi_to_yougo_btn_click() if self.imi_to_yougo_btn.winfo_ismapped() else None)
        root.bind("e", lambda event: self.mix_btn_click() if self.mix_btn.winfo_ismapped() else None)

    def create_widgets(self):
        style = ttk.Style()
        style.configure("default.TButton", font=("メイリオ", 16))

        # タイトルラベル
        self.warning_label = tk.Label(self)
        self.warning_label['text'] = ''
        self.warning_label['font'] = config.checkbtn_font
        self.warning_label.pack()

        # メニューに戻るボタン
        self.return_btn = ttk.Button(self)
        self.return_btn['text'] = 'メニューに戻る(m)'
        self.return_btn['style'] = "default.TButton"
        self.return_btn['width'] = config.default_button_width
        self.return_btn['padding'] = config.default_button_padding
        self.return_btn['command'] = self.change_index
        self.return_btn.bind('<Return>', self.change_index)
        self.return_btn.pack(side='bottom',anchor='sw')

        # 用語to意味ボタン
        self.yougo_to_imi_btn = ttk.Button(self)
        self.yougo_to_imi_btn['text'] = '用語から説明を答える(q)'
        self.yougo_to_imi_btn['style'] = "default.TButton"
        self.yougo_to_imi_btn['width'] = config.default_button_width
        self.yougo_to_imi_btn['padding'] = config.default_button_padding
        self.yougo_to_imi_btn['command'] = self.yougo_to_imi_btn_click
        self.yougo_to_imi_btn.bind('<Return>', self.yougo_to_imi_btn_click)
        self.yougo_to_imi_btn.place(x='1058', y='40')

        # 意味to用語ボタン
        self.imi_to_yougo_btn = ttk.Button(self)
        self.imi_to_yougo_btn['text'] = '説明から用語を答える(w)'
        self.imi_to_yougo_btn['style'] = "default.TButton"
        self.imi_to_yougo_btn['width'] = config.default_button_width
        self.imi_to_yougo_btn['padding'] = config.default_button_padding
        self.imi_to_yougo_btn['command'] = self.imi_to_yougo_btn_click
        self.imi_to_yougo_btn.bind('<Return>', self.imi_to_yougo_btn_click)
        self.imi_to_yougo_btn.place(x='1058', y='120')

        # ミックスボタン
        self.mix_btn = ttk.Button(self)
        self.mix_btn['text'] = 'ミックス！(e)'
        self.mix_btn['style'] = "default.TButton"
        self.mix_btn['width'] = config.default_button_width
        self.mix_btn['padding'] = config.default_button_padding
        self.mix_btn['command'] = self.mix_btn_click
        self.mix_btn.bind('<Return>', self.mix_btn_click)
        self.mix_btn.place(x='1058', y='200')

        # チェックボックスすべてのブーリアンバー
        self.is_checklist =[tk.BooleanVar() for _ in range(11)]

        # チェックボタン1
        check_btn_1 = tk.Checkbutton(self)
        check_btn_1['text'] = config.chapter_1_text
        check_btn_1['font'] = config.checkbtn_font
        check_btn_1['variable'] = self.is_checklist[0]
        check_btn_1.place(x='40', y='40')

        # チェックボタン2
        check_btn_2 = tk.Checkbutton(self)
        check_btn_2['text'] = config.chapter_2_text
        check_btn_2['font'] = config.checkbtn_font
        check_btn_2['variable'] = self.is_checklist[1]
        check_btn_2.place(x='40', y='90')

        # チェックボタン3
        check_btn_3 = tk.Checkbutton(self)
        check_btn_3['text'] = config.chapter_3_text
        check_btn_3['font'] = config.checkbtn_font
        check_btn_3['variable'] = self.is_checklist[2]
        check_btn_3.place(x='40', y='140')

        # チェックボタン4
        check_btn_4 = tk.Checkbutton(self)
        check_btn_4['text'] = config.chapter_4_text
        check_btn_4['font'] = config.checkbtn_font
        check_btn_4['variable'] = self.is_checklist[3]
        check_btn_4.place(x='40', y='190')

        # チェックボタン5
        check_btn_5 = tk.Checkbutton(self)
        check_btn_5['text'] = config.chapter_5_text
        check_btn_5['font'] = config.checkbtn_font
        check_btn_5['variable'] = self.is_checklist[4]
        check_btn_5.place(x='40', y='240')

        # チェックボタン6
        check_btn_6 = tk.Checkbutton(self)
        check_btn_6['text'] = config.chapter_6_text
        check_btn_6['font'] = config.checkbtn_font
        check_btn_6['variable'] = self.is_checklist[5]
        check_btn_6.place(x='40', y='290')

        # チェックボタン7
        check_btn_7 = tk.Checkbutton(self)
        check_btn_7['text'] = config.chapter_7_text
        check_btn_7['font'] = config.checkbtn_font
        check_btn_7['variable'] = self.is_checklist[6]
        check_btn_7.place(x='40', y='340')

        # チェックボタン8
        check_btn_8 = tk.Checkbutton(self)
        check_btn_8['text'] = config.chapter_8_text
        check_btn_8['font'] = config.checkbtn_font
        check_btn_8['variable'] = self.is_checklist[7]
        check_btn_8.place(x='40', y='390')

        # チェックボタン9
        check_btn_9 = tk.Checkbutton(self)
        check_btn_9['text'] = config.chapter_9_text
        check_btn_9['font'] = config.checkbtn_font
        check_btn_9['variable'] = self.is_checklist[8]
        check_btn_9.place(x='40', y='440')

        # チェックボタン10
        check_btn_10 = tk.Checkbutton(self)
        check_btn_10['text'] = config.chapter_10_text
        check_btn_10['font'] = config.checkbtn_font
        check_btn_10['variable'] = self.is_checklist[9]
        check_btn_10.place(x='40', y='490')

        # チェックボタン11
        check_btn_11 = tk.Checkbutton(self)
        check_btn_11['text'] = config.chapter_11_text
        check_btn_11['font'] = config.checkbtn_font
        check_btn_11['variable'] = self.is_checklist[10]
        check_btn_11.place(x='40', y='540')

    # どれにもチェックを入れてないの防止する
    def check_checcker(self):
        for i in self.is_checklist:
            if i.get():
                return True
        return False

    def change_index(self,event=None):
        # 現在のフレームを非表示にする
        self.pack_forget()
        # 新しいフレームを作成して表示する
        app = Application_index(self.root)
        app.pack()

    def change_quest(self,event=None):
        if not self.check_checcker():
            self.warning_label['text'] = 'どれかにチェックを入れて～(´；ω；`)ｳｩｩ'
        else:

            # 現在のフレームを非表示にする
            self.pack_forget()
            # 新しいフレームを作成して表示する
            app = Application_quest(self.root ,is_checklist = self.is_checklist ,quest_mode = self.quest_mode)
            app.pack()

    # ボタンを押したときの挙動
    def yougo_to_imi_btn_click(self,event=None):
        self.quest_mode = 1
        self.change_quest()

    def imi_to_yougo_btn_click(self,event=None):
        self.quest_mode = 2
        self.change_quest()

    def mix_btn_click(self,event=None):
        self.quest_mode = 3
        self.change_quest()

class Application_quest(tk.Frame):
    def __init__(self, root=None, is_checklist = None ,quest_mode = None):
        super().__init__(root, width=1344, height=756, borderwidth=1, relief='solid')
        self.root = root
        self.pack(anchor='center',expand=1)
        self.pack_propagate(0)
        self.create_widgets()
        root.bind("q", lambda event: self.create_quest() if self.next_btn.winfo_ismapped() else None)
        root.bind("m", lambda event: self.change_index() if self.return_btn.winfo_ismapped() else None)
        root.bind("1", lambda event: self.choose_answer(num=0) if self.answer_1_btn.winfo_ismapped() else None)
        root.bind("2", lambda event: self.choose_answer(num=1) if self.answer_2_btn.winfo_ismapped() else None)
        root.bind("3", lambda event: self.choose_answer(num=2) if self.answer_3_btn.winfo_ismapped() else None)
        root.bind("4", lambda event: self.choose_answer(num=3) if self.answer_4_btn.winfo_ismapped() else None)
        self.file_name = 'FE単語意味頑張るマン.xlsx'
        self.is_checklist = is_checklist
        self.decision_answers = []
        self.decision_quest = []
        self.quest_mode = quest_mode
        print("クエストモードは" + str(self.quest_mode))
        # 初期問題作成
        self.create_quest()

    def create_widgets(self):
        style = ttk.Style()
        style.configure("default.TButton", font=("メイリオ", 16))

        # タイトルラベル
        self.label = tk.Label(self)
        self.label['text'] = ''
        self.label['font'] = config.checkbtn_font
        self.label.pack()

        # メニューに戻るボタン
        self.return_btn = ttk.Button(self)
        self.return_btn['text'] = 'メニューに戻る(m)'
        self.return_btn['style'] = "default.TButton"
        self.return_btn['width'] = config.default_button_width
        self.return_btn['padding'] = config.default_button_padding
        self.return_btn['command'] = self.change_index
        self.return_btn.bind('<Return>', self.change_index)
        self.return_btn.pack(side='bottom',anchor='sw')

        # １ボタン
        self.answer_1_btn = ttk.Button(self)
        self.answer_1_btn['text'] = '1'
        self.answer_1_btn['style'] = "default.TButton"
        self.answer_1_btn['width'] = config.default_button_width
        self.answer_1_btn['padding'] = config.default_button_padding
        self.answer_1_btn['command'] = lambda: self.choose_answer(num=0)
        self.answer_1_btn.bind('<Return>', lambda: self.choose_answer(num=0))

        # 2ボタン
        self.answer_2_btn = ttk.Button(self)
        self.answer_2_btn['text'] = '2'
        self.answer_2_btn['style'] = "default.TButton"
        self.answer_2_btn['width'] = config.default_button_width
        self.answer_2_btn['padding'] = config.default_button_padding
        self.answer_2_btn['command'] = lambda: self.choose_answer(num=1)
        self.answer_2_btn.bind('<Return>', lambda: self.choose_answer(num=1))

        # 3ボタン
        self.answer_3_btn = ttk.Button(self)
        self.answer_3_btn['text'] = '3'
        self.answer_3_btn['style'] = "default.TButton"
        self.answer_3_btn['width'] = config.default_button_width
        self.answer_3_btn['padding'] = config.default_button_padding
        self.answer_3_btn['command'] = lambda: self.choose_answer(num=2)
        self.answer_3_btn.bind('<Return>', lambda: self.choose_answer(num=2))

        # 4ボタン
        self.answer_4_btn = ttk.Button(self)
        self.answer_4_btn['text'] = '4'
        self.answer_4_btn['style'] = "default.TButton"
        self.answer_4_btn['width'] = config.default_button_width
        self.answer_4_btn['padding'] = config.default_button_padding
        self.answer_4_btn['command'] = lambda: self.choose_answer(num=3)
        self.answer_4_btn.bind('<Return>', lambda: self.choose_answer(num=3))

        # 次へボタン
        self.next_btn = ttk.Button(self)
        self.next_btn['text'] = '次へ(q)'
        self.next_btn['style'] = "default.TButton"
        self.next_btn['width'] = config.default_button_width
        self.next_btn['padding'] = config.default_button_padding
        self.next_btn['command'] = self.create_quest
        self.next_btn.bind('<Return>', self.create_quest)

        # 問題ラベル
        quest_label = tk.Label(self)
        # quest_label['width'] = 1000
        quest_label['font'] = config.message_font
        quest_label['text'] = "Q."
        quest_label.place(x=20,y=40)

        # 問題メッセージ
        self.quest_message = tk.Message(self)
        self.quest_message['width'] = 980
        self.quest_message['font'] = config.message_font
        self.quest_message['text'] = ""
        self.quest_message.place(x=40,y=40)

        # 解答ラベル1
        self.answer_label_1 = tk.Label(self)
        self.answer_label_1['font'] = config.message_font
        self.answer_label_1['text'] = "1."
        self.answer_label_1.place(x=20,y=180)

        # 解答メッセージ1
        self.answer_message_1 = tk.Message(self)
        self.answer_message_1['width'] = 980
        self.answer_message_1['font'] = config.message_font
        self.answer_message_1['text'] = ""
        self.answer_message_1.place(x=40,y=180)

        # 解答ラベル2
        self.answer_label_2 = tk.Label(self)
        self.answer_label_2['font'] = config.message_font
        self.answer_label_2['text'] = "2."
        self.answer_label_2.place(x=20,y=300)

        # 解答メッセージ2
        self.answer_message_2 = tk.Message(self)
        self.answer_message_2['width'] = 980
        self.answer_message_2['font'] = config.message_font
        self.answer_message_2['text'] = ""
        self.answer_message_2.place(x=40,y=300)

        # 解答ラベル3
        self.answer_label_3 = tk.Label(self)
        self.answer_label_3['font'] = config.message_font
        self.answer_label_3['text'] = "3."
        self.answer_label_3.place(x=20,y=420)

        # 解答メッセージ3
        self.answer_message_3 = tk.Message(self)
        self.answer_message_3['width'] = 980
        self.answer_message_3['font'] = config.message_font
        self.answer_message_3['text'] = ""
        self.answer_message_3.place(x=40,y=420)

        # 解答ラベル4
        self.answer_label_4 = tk.Label(self)
        self.answer_label_4['font'] = config.message_font
        self.answer_label_4['text'] = "4."
        self.answer_label_4.place(x=20,y=540)

        # 解答メッセージ4
        self.answer_message_4 = tk.Message(self)
        self.answer_message_4['width'] = 980
        self.answer_message_4['font'] = config.message_font
        self.answer_message_4.place(x=40,y=540)

    def change_index(self,event=None):
        # 現在のフレームを非表示にする
        self.pack_forget()
        # 新しいフレームを作成して表示する
        app = Application_index(self.root)
        app.pack()

    # チェックボックスより章を決定
    def decision_chapter_number(self):
        while True:
            # 1～11の数字をランダムに生成
            rand_num = random.randint(1, 11)
            # self.is_checklistのrand_num番目がTrueの場合、rand_numを返す
            if self.is_checklist[rand_num - 1].get():
                print("選ばれた章は" + str(rand_num))
                return rand_num
    def yougo_to_imi_create(self):
        self.answer_message_1['text'] = config.ws[f'D{self.decision_answers[0]}'].value
        self.answer_message_2['text'] = config.ws[f'D{self.decision_answers[1]}'].value
        self.answer_message_3['text'] = config.ws[f'D{self.decision_answers[2]}'].value
        self.answer_message_4['text'] = config.ws[f'D{self.decision_answers[3]}'].value

        # 問題を一つだけ作成
        self.decision_quest = random.sample(self.decision_answers,1)
        self.quest_message['text'] = config.ws[f'B{self.decision_quest[0]}'].value + "　を説明したものはどれか？"
        print("今回の答えは" + str((self.decision_answers.index(self.decision_quest[0])) + 1))
    def imi_to_yougo_create(self):
        self.answer_message_1['text'] = config.ws[f'B{self.decision_answers[0]}'].value
        self.answer_message_2['text'] = config.ws[f'B{self.decision_answers[1]}'].value
        self.answer_message_3['text'] = config.ws[f'B{self.decision_answers[2]}'].value
        self.answer_message_4['text'] = config.ws[f'B{self.decision_answers[3]}'].value

        # 問題を一つだけ作成
        self.decision_quest = random.sample(self.decision_answers,1)
        self.quest_message['text'] = config.ws[f'D{self.decision_quest[0]}'].value + "　はどれを説明したものか？"
        print("今回の答えは" + str((self.decision_answers.index(self.decision_quest[0])) + 1))
    #問題を作成
    def create_quest(self,event=None):
        # ボタン配置変更
        self.answer_1_btn.place(x='1058', y='40')
        self.answer_2_btn.place(x='1058', y='120')
        self.answer_3_btn.place(x='1058', y='200')
        self.answer_4_btn.place(x='1058', y='280')
        self.next_btn.place_forget()

        # 選択肢の色を戻す
        self.answer_label_1["fg"] = "black"
        self.answer_message_1["fg"] = "black"
        self.answer_label_2["fg"] = "black"
        self.answer_message_2["fg"] = "black"
        self.answer_label_3["fg"] = "black"
        self.answer_message_3["fg"] = "black"
        self.answer_label_4["fg"] = "black"
        self.answer_message_4["fg"] = "black"

        # ラベルを初期化
        self.label['text'] =""
        #
        chpter_number = self.decision_chapter_number()
        # G列が選ばれた章の行番号を取得
        rows = []
        for i in range(1, config.ws.max_row + 1):
            if config.ws.cell(row=i, column=7).value == chpter_number:
                rows.append(i)

        # 一意に4つ作成
        self.decision_answers = random.sample(rows,4)

        # クエストモードにより取得列を変える
        if self.quest_mode == 1:
            self.yougo_to_imi_create()
        elif self.quest_mode ==2:
            self.imi_to_yougo_create()
        else:
            if random.randint(1,2) == 1:
                self.yougo_to_imi_create()
            else:
                self.imi_to_yougo_create()

    # 答えをクリック
    def choose_answer(self,num=None):
        # ボタン配置変更
        self.answer_1_btn.place_forget()
        self.answer_3_btn.place_forget()
        self.answer_2_btn.place_forget()
        self.answer_4_btn.place_forget()
        self.next_btn.place(x='1058', y='699')

        # 正解の選択肢の色を赤に
        if self.decision_answers.index(self.decision_quest[0]) == 0:
            self.answer_label_1["fg"] = "red"
            self.answer_message_1["fg"] = "red"
        elif self.decision_answers.index(self.decision_quest[0]) == 1:
            self.answer_label_2["fg"] = "red"
            self.answer_message_2["fg"] = "red"
        elif self.decision_answers.index(self.decision_quest[0]) == 2:
            self.answer_label_3["fg"] = "red"
            self.answer_message_3["fg"] = "red"
        else :
            self.answer_label_4["fg"] = "red"
            self.answer_message_4["fg"] = "red"

        # 正解判定
        if self.decision_answers[num] == self.decision_quest[0]:
            print("正解！")
            self.label['text'] = "正解！"
            self.label['fg'] ="red"
            quest_cell = config.ws['{}{}'.format('E',self.decision_quest[0])]
            quest_cell.value = quest_cell.value + 1
            config.wb.save(config.file_name)

        else:
            print("不正解・・・")
            self.label['text'] ="不正解・・・"
            self.label['fg'] ="blue"
            quest_cell = config.ws['{}{}'.format('F',self.decision_quest[0])]
            quest_cell.value = quest_cell.value + 1
            config.wb.save(config.file_name)

class Application_grades(tk.Frame):
    def __init__(self, root=None):
        super().__init__(root, width=1344, height=756, borderwidth=1, relief='solid')
        self.root = root
        self.pack(anchor='center',expand=1)
        self.pack_propagate(0)
        self.create_widgets()
        root.bind("m", lambda event: self.change_index() if self.return_btn.winfo_ismapped() else None)

        for i in range(11):
            self.calc_grades(i)

    def create_widgets(self):
        style = ttk.Style()
        style.configure("default.TButton", font=("メイリオ", 16))

        # メニューに戻るボタン
        self.return_btn = ttk.Button(self)
        self.return_btn['text'] = 'メニューに戻る(m)'
        self.return_btn['style'] = "default.TButton"
        self.return_btn['width'] = config.default_button_width
        self.return_btn['padding'] = config.default_button_padding
        self.return_btn['command'] = self.change_index
        self.return_btn.bind('<Return>', self.change_index)
        self.return_btn.pack(side='bottom',anchor='sw')

        # 線を引くための定義
        canvas = tk.Canvas(self, width=1500, height=800)
        canvas.pack()

        # トピックラベル
        chapter_label_0 = tk.Label(self)
        chapter_label_0['width'] = 32
        # chapter_label_0['relief'] = 'solid'
        chapter_label_0['text'] = "成績：チャプター"
        chapter_label_0['font'] = config.checkbtn_font
        chapter_label_0['anchor'] = tk.W
        chapter_label_0.place(x='40', y='20')

        chapter_label_0 = tk.Label(self)
        chapter_label_0['width'] = 10
        # chapter_label_0['relief'] = 'solid'
        chapter_label_0['text'] = "回答数"
        chapter_label_0['font'] = config.checkbtn_font
        chapter_label_0['anchor'] = tk.E
        chapter_label_0.place(x='600', y='20')

        chapter_label_0 = tk.Label(self)
        chapter_label_0['width'] = 10
        # chapter_label_0['relief'] = 'solid'
        chapter_label_0['text'] = "正解率"
        chapter_label_0['font'] = config.checkbtn_font
        chapter_label_0['anchor'] = tk.E
        chapter_label_0.place(x='800', y='20')

        chapter_label_0 = tk.Label(self)
        chapter_label_0['width'] = 20
        # chapter_label_0['relief'] = 'solid'
        chapter_label_0['text'] = "リセットボタン(未実装)"
        chapter_label_0['font'] = config.checkbtn_font
        chapter_label_0['anchor'] = tk.W
        chapter_label_0.place(x='1054', y='20')

        # 成績のウィジェット達
        self.number_of_answers_messages=[]
        self.accuracy_rate_messages=[]
        self.reset_btns = []

        for i in range(11):
            chapter_label = tk.Label(self)
            chapter_label['width'] = 32
            # chapter_label['relief'] = 'solid'
            chapter_label['text'] = config.chapter_list[i]
            chapter_label['font'] = config.checkbtn_font
            chapter_label['anchor'] = tk.W
            chapter_label.place(x='40', y=str(80 + i*55))

            number_of_answers_message = tk.Label(self)
            number_of_answers_message['width'] = 10
            # number_of_answers_message['relief'] = 'solid'
            number_of_answers_message['font'] = config.checkbtn_font
            number_of_answers_message['anchor'] = tk.E
            number_of_answers_message.place(x='600', y=str(80 + i*55))

            accuracy_rate_message = tk.Label(self)
            accuracy_rate_message['width'] = 10
            # accuracy_rate_message['relief'] = 'solid'
            accuracy_rate_message['font'] = config.checkbtn_font
            accuracy_rate_message['anchor'] = tk.E
            accuracy_rate_message.place(x='800', y=str(80 + i*55))

            reset_btn = ttk.Button(self)
            reset_btn['text'] = '第'+ str(i+1) +'章をリセットする'
            reset_btn['style'] = "default.TButton"
            reset_btn['width'] = config.default_button_width
            reset_btn['padding'] = config.default_button_padding
            # reset_btn['command'] = lambda: self.reset_btn_click(i)
            # reset_btn.bind('<Return>', self.reset_btn_click(i))
            reset_btn.place(x='1054',y=str(76 + i*55))

            self.number_of_answers_messages.append(number_of_answers_message)
            self.accuracy_rate_messages.append(accuracy_rate_message)
            self.reset_btns.append(reset_btn)

            canvas.create_line(0, 76 + i*55 , 1500, 76 + i*55 )

    def reset_btn_click(self,i) :
        num = str(i)
        print(num + "が押されました。")

    def calc_grades(self,i):
        grade_chapter_namber = i +1
        rows = []
        total_e = 0
        total_f = 0
        for j in range(1, config.ws.max_row + 1):
            if config.ws.cell(row=j, column=7).value == grade_chapter_namber:
                rows.append(j)

        for row in rows:
            total_e += config.ws.cell(row=row, column=5).value
            total_f += config.ws.cell(row=row, column=6).value

            number_of_answers = total_e + total_f
            accuracy_rate = total_e / (total_e + total_f) * 100 if number_of_answers > 0 else '0'
            self.number_of_answers_messages[i]["text"] = str(number_of_answers) + "回"
            self.accuracy_rate_messages[i]["text"] = str(int(accuracy_rate)) + "%"

    def change_index(self,event=None):
        # 現在のフレームを非表示にする
        self.pack_forget()
        # 新しいフレームを作成して表示する
        app = Application_index(self.root)
        app.pack()

class Application_data(tk.Frame):
    def __init__(self, root=None):
        super().__init__(root, width=1344, height=756, borderwidth=1, relief='solid')
        self.root = root
        self.pack(anchor='center',expand=1)
        self.pack_propagate(0)
        self.create_widgets()
        root.bind("m", lambda event: self.change_index() if self.return_btn.winfo_ismapped() else None)

    def create_widgets(self):
        style = ttk.Style()
        style.configure("default.TButton", font=("メイリオ", 16))

        # タイトルラベル
        label = tk.Label(self)
        label['text'] = 'ここはデータ変更ページ'
        label['font'] = config.titlefont
        label.pack()

        # メニューに戻るボタン
        self.return_btn = ttk.Button(self)
        self.return_btn['text'] = 'メニューに戻る(m)'
        self.return_btn['style'] = "default.TButton"
        self.return_btn['width'] = config.default_button_width
        self.return_btn['padding'] = config.default_button_padding
        self.return_btn['command'] = self.change_index
        self.return_btn.bind('<Return>', self.change_index)
        self.return_btn.pack(side='bottom',anchor='sw')

    def change_index(self,event=None):
        # 現在のフレームを非表示にする
        self.pack_forget()
        # 新しいフレームを作成して表示する
        app = Application_index(self.root)
        app.pack()

root = tk.Tk()
root.title('FE単語意味頑張るマン')
root.geometry('1344x756')
# root.option_add("*size", 160)
# root.option_add("*foreground", "white")
# root.option_add("*background","black")
app = Application_index(root=root)
app.pack()
root.mainloop()


import json
from django.views import View
from .models import User
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse
import json
import requests
# Create your views here.

def get_users():

        url = 'https://jsonplaceholder.typicode.com/users'
        response = requests.get(url)
        users = response.json()

        for i in users:
            User.objects.get_or_create(
                name = i['name'],
                user_name = i['username'],
                email = i['email'],
            )

class UserView(View):

    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)

    def get(self, request, id=0):
        get_users()
        if id > 0:
            users = list(User.objects.filter(id=id).values())
            if len(users) > 0:
                user = users[0]
                datos={'message':"success", 'user': user}
            else:
                datos={'message':  'user not found'}
            return JsonResponse(datos)
        else:
            users = list(User.objects.values())
            if len(users) > 0:
                datos={'message':"success", 'users': users}
            else:
                datos={'message':  'users not found'}
            return JsonResponse(datos)

    def post(self, request):
        jd = json.loads(request.body)
        User.objects.create(name=jd['name'], user_name=jd['user_name'], email=jd['email'])
        datos={'message':"success"}
        return JsonResponse(datos)

    def put(self, request, id):
        jd = json.loads(request.body)
        users = list(User.objects.filter(id=id).values())
        if len(users) > 0:
            user = User.objects.get(id=id)
            user.name =jd["name"]
            user.user_name =jd["user_name"]
            user.email =jd["email"]
            user.save()
            datos={'message':"success"}
        else:
            datos={'message':  'user not found'}
        return JsonResponse(datos)

    def delete(self, request, id):
        users = list(User.objects.filter(id=id).values())
        if len(users) > 0:
            User.objects.filter(id=id).delete()
            datos={'message':"success"}
        else:
            datos={'message':  'user not found'}
        return JsonResponse(datos)

# def users(request):
#     #pull data from third party rest api
#     response = requests.get('https://jsonplaceholder.typicode.com/users')
#     #convert reponse data into json
#     users = response.json()
#     print(users)
#     return HttpResponse(response)


from __future__ import annotations

from abc import ABCMeta, abstractmethod
from dataclasses import dataclass
from enum import Enum, auto
from concurrent.futures import ThreadPoolExecutor
from contextlib import AbstractContextManager

from common import types as T, time
from common.logging import log
from common.models.task import ExitCode, Task
from common.models.filesystems.types import BaseFilesystem
from .exceptions import NoCommonChecksumAlgorithm, PeriodNotStarted, NoTasksAvailable

class BaseStateProtocol(metaclass=ABCMeta):
    """
    Abstract base class for encapsulating communication with the
    underlying persistence engine (e.g., managing connections,
    performing queries, etc.) and application-level classes

    NOTE Must be thread-safe

    Implementations required:
    * filesystem_convertor :: *args x **kwargs -> BaseFilesystem
    """
    _filesystems:T.Dict[str, BaseFilesystem]

    def register_filesystems(self, *filesystems:BaseFilesystem) -> None:
        # Add filesystem instances to our internal mapping
        if not hasattr(self, "_filesystems"):
            self._filesystems = {}

        self._filesystems = {
            **self._filesystems,
            **{fs.name: fs for fs in filesystems}
        }

    @abstractmethod
    def filesystem_convertor(self, *args, **kwargs) -> BaseFilesystem:
        """
        Convert a persisted representation of a filesystem into its
        respective instance

        @param   *args, **kwargs        Necessary data from the
                                        persistence engine to map to the
                                        appropriate filesystem instance
        @raises  NoFilesystemConvertor  Ambiguous conversion
        @return  Filesystem instance
        """

FORCIBLY_TERMINATED  = ExitCode(-3)

# Verification failure handling
_MISMATCHED_SIZE     = ExitCode(-1)
_MISMATCHED_CHECKSUM = ExitCode(-2)

class _VerificationFailure(Exception):
    """ Raised on verification failure """

@dataclass
class _DurationMixin:
    """ Model for durations """
    start:T.Optional[T.DateTime]
    finish:T.Optional[T.DateTime]

    @property
    def runtime(self) -> T.TimeDelta:
        """ Phase runtime """
        if self.start is None:
            raise PeriodNotStarted("Period has yet to start")

        until = self.finish or time.now()
        return until - self.start

    @property
    def complete(self) -> bool:
        # Truthy once there's a finish timestamp
        return self.finish is not None

class _BaseDurationMixin(_DurationMixin, AbstractContextManager, metaclass=ABCMeta):
    """
    Abstract base class for setting the start and finish timestamps

    Implementations required:
    * init :: () -> T.DateTime
    * stop :: () -> T.DateTime
    """
    @abstractmethod
    def init(self) -> T.DateTime:
        """ Persist and return the duration start timestamp """

    @abstractmethod
    def stop(self) -> T.DateTime:
        """ Persist and return the duration finish timestamp """

    def __enter__(self) -> None:
        self.init()

    def __exit__(self, *exception) -> bool:
        self.stop()
        return False

@dataclass(frozen=True)
class JobThroughput:
    """ Model of throughput rates between filesystems """
    transfer_rate:float  # bytes/second
    failure_rate:float   # Probability

class JobPhase(Enum):
    """ Enumeration of job phases """
    Preparation = auto()
    Transfer    = auto()

# Convenience aliases
_PREPARATION = JobPhase.Preparation
_TRANSFER    = JobPhase.Transfer

class BasePhaseStatus(_BaseDurationMixin, metaclass=ABCMeta):
    """ Abstract base class for phase status """
    def __bool__(self) -> bool:
        return not self.complete

class _TaskOverviewMixin:
    """ Model for expressing job task overview """
    pending:int
    running:int
    failed:int
    succeeded:int

class BaseJobStatus(_TaskOverviewMixin, metaclass=ABCMeta):
    """
    Abstract base class for job and phase status

    Implementations required:
    * throughput :: BaseFilesystem x BaseFilesystem -> JobThroughput
    * phase      :: JobPhase -> BasePhaseStatus
    """
    def __bool__(self) -> bool:
        # Truthy when the preparation phase is still in progress or
        # there are still jobs pending (i.e., in progress)
        return self.phase(_PREPARATION) or self.pending > 0

    @abstractmethod
    def throughput(self, source:BaseFilesystem, target:BaseFilesystem) -> JobThroughput:
        """
        Return the throughput rates between the given filesystems

        @param   source            Source filesystem
        @param   target            Target filesystem
        @raise   NoThroughputData  No throughput data available
        @return  Job throughput
        """

    @abstractmethod
    def phase(self, phase:JobPhase) -> BasePhaseStatus:
        """
        Return the phase status for the specified phase

        @param   phase             Job phase
        @raise   PeriodNotStarted  Phase has yet to start
        @return  Phase status
        """

    @property
    def complete(self) -> bool:
        # Truthy when the transfer phase has ended (n.b., which is
        # dependent on the preparation phase ending)
        # NOTE Completion does not imply success!
        try:
            return not self.phase(_TRANSFER)

        except PeriodNotStarted:
            return False

class DataOrigin(Enum):
    """ Enumeration of data origins """
    Source = auto()
    Target = auto()

# Convenience aliases
_SOURCE = DataOrigin.Source
_TARGET = DataOrigin.Target

@dataclass
class _AttemptMixin:
    """ Model of task attempts """
    task:Task

class BaseAttempt(_AttemptMixin, _BaseDurationMixin, metaclass=ABCMeta):
    """
    Abstract base class for task attempts

    Implementations required:
    * size      :: DataOrigin -> int         Must be thread-safe!
    * checksum  :: DataOrigin x str -> int   Must be thread-safe!
    * exit_code :: Getter () -> ExitCode / Setter ExitCode -> None
    """
    @abstractmethod
    def size(self, origin:DataOrigin) -> int:
        """
        Persist and return the origin's data size

        NOTE Implementation must be thread-safe
        """

    @abstractmethod
    def checksum(self, origin:DataOrigin, algorithm:str) -> str:
        """
        Persist and return the origin's data checksum

        NOTE Implementation must be thread-safe
        """

    @property
    @abstractmethod
    def exit_code(self) -> ExitCode:
        """
        Fetch the task's exit code for this attempt, if available

        @raise  DataNotReady  No exit code yet available
        """

    @exit_code.setter
    @abstractmethod
    def exit_code(self, value:ExitCode) -> None:
        """ Persist the task's exit code for this attempt """

    def _get_source_properties(self, *algorithms:str) -> T.Tuple[int, T.Dict[str, str]]:
        # Fetch the source data's size and checksums using the specified
        # algorithms (to be run internally in a separate thread)
        return self.size(_SOURCE), \
               {algorithm: self.checksum(_SOURCE, algorithm) for algorithm in algorithms}

    def __call__(self) -> bool:
        """ Attempt the transfer task """
        # The context manager sets the attempt start and finish timestamps
        with self:
            task = self.task
            log.info(f"Attempting transfer of "
                     f"{task.source.address} on {task.source.filesystem} to "
                     f"{task.target.address} on {task.target.filesystem}")

            with ThreadPoolExecutor(max_workers=1) as executor:
                # TODO Different/multiple checksum algorithms
                properties = executor.submit(self._get_source_properties, "md5")

                # Run task in main tread and join on properties thread
                success = self.task()
                source_size, source_checksums = properties.result()

            if not success:
                log.warning(f"Attempt failed with exit code {success.exit_code}")

            else:
                log.info(f"Data copied; verifying...")

                try:
                    target_size = self.size(_TARGET)
                    if source_size != target_size:
                        log.warning(f"Attempt failed: "
                                    f"Source is {source_size} bytes; "
                                    f"target is {target_size} bytes")

                        success = _MISMATCHED_SIZE
                        raise _VerificationFailure()

                    # TODO Different/multiple checksum algorithms
                    source_checksum = source_checksums["md5"]
                    target_checksum = self.checksum(_TARGET, "md5")
                    if source_checksum != target_checksum:
                        log.warning(f"Attempt failed: "
                                    f"Source has checksum {source_checksum}; "
                                    f"target has checksum {target_checksum}")

                        success = _MISMATCHED_CHECKSUM
                        raise _VerificationFailure()

                    # TODO Data metadata: There is no need to set this
                    # for each intermediary stage; just set the final
                    # target metadata to that of the original source.
                    # Think about how to implement this...

                except _VerificationFailure:
                    pass

            self.exit_code = success
            return bool(success)

@dataclass
class DependentTask:
    """ Model of sequence of task dependencies """
    task:Task
    dependency:T.Optional[DependentTask] = None

class BaseJob(T.Iterator[BaseAttempt], metaclass=ABCMeta):
    """
    Abstract base class for jobs

    Implementations required:
    * __init__     :: Any x String x Optional[Identifier] x Boolean -> None
    * __iadd__     :: DependentTask -> BaseJob
    * attempt      :: Optional[TimeDelta] -> BaseAttempt
    * max_attempts :: Getter () -> Optional[Integer] / Setter Integer -> None
    * status       :: Getter () -> BaseJobStatus
    * metadata     :: Getter () -> SimpleNamespace
    * set_metadata :: kwargs -> None
    """
    _client_id:str
    _job_id:T.Identifier

    @abstractmethod
    def __init__(self, state:BaseStateProtocol, *, client_id:str, job_id:T.Optional[T.Identifier] = None, force_restart:bool = False) -> None:
        """
        Constructor

        @param  state          Encapsulation of the persisted state
        @param  client_id      Client identifier
        @param  job_id         Job ID for a running job
        @param  force_restart  Whether to forcibly resume a job
        """

    @abstractmethod
    def __iadd__(self, task:DependentTask) -> BaseJob:
        """ Add a sequence of dependent tasks to the job """
        # NOTE The root source is assumed to exist, so we can query its
        # size. Ideally, this size should be persisted along with the
        # task, as THERE IS NO OTHER INTERFACE FOR DOING SO. Without it,
        # it would be impossible to make transfer rate calculations.

    def __iter__(self) -> BaseJob:
        return self

    def __next__(self) -> BaseAttempt:
        # The next pending task to attempt, *regardless* of time limit
        try:
            return self.attempt()

        except NoTasksAvailable:
            if self.status.complete:
                raise StopIteration()

    @property
    def job_id(self) -> T.Identifier:
        return self._job_id

    @abstractmethod
    def attempt(self, time_limit:T.Optional[T.TimeDelta] = None) -> BaseAttempt:
        """
        Fetch the next pending task to attempt, given the optional time
        limit (which is ignored, if no timing statistics are available)

        @param   time_limit  Only fetch attempts that are predicted to
                             complete within this duration (optional;
                             defaults to None, to ignore time limits)
        @return  Attempt
        """

    @property
    @abstractmethod
    def max_attempts(self) -> int:
        """ Get the maximum number of attempts for a task """

    @max_attempts.setter
    @abstractmethod
    def max_attempts(self, value:int) -> None:
        """ Set the maximum number of attempts for a task """

    @property
    @abstractmethod
    def status(self) -> BaseJobStatus:
        """ Get the current job status """

    # TODO Make the client metadata interface nicer

    @property
    @abstractmethod
    def metadata(self) -> T.SimpleNamespace:
        """ Get the job metadata """

    @abstractmethod
    def set_metadata(self, **metadata:str) -> None:
        """ Set (insert/update) key-value metadata """


from fastapi.testclient import TestClient

from app.main import app

class TestRequests:
    def setup_class(self):
        self.clients = [
            TestClient(app),
            TestClient(app),
            TestClient(app),
            TestClient(app),
        ]
        self.players = [
            {
                "username": "111",
                "password": "1",
                "avatar": "lama",
            },
            {
                "username": "222",
                "password": "2",
                "avatar": "lama",
            },
            {
                "username": "333",
                "password": "3",
                "avatar": "lama",
            },
            {
                "username": "444",
                "password": "4",
                "avatar": "lama",
            },
        ]
        self.game_ids = []
        self.cards = []

    # def test_create_users(self):
    #     for player in self.players:
    #         res = self.clients[0].post("v1/create_user", json=player)
    #         assert res.status_code == 200
    #         assert "uid" in res.json()
    #         assert res.json()["username"] == player["username"]
    #         player["uid"] = res.json()["uid"]

    def test_login_users(self):
        for i, client in enumerate(self.clients):
            res = client.post("v1/token", data=self.players[i])
            assert res.status_code == 200
            assert "access_token" in res.json()
            assert "token_type" in res.json()
            assert res.json()["token_type"] == "bearer"

            token = res.json()["access_token"]
            self.clients[i].headers.update(
                {"Authorization": f"Bearer {token}"})

    def test_request_initialize_game(self):
        res = self.clients[0].post("v1/games?seed=1",
                                   json={"game_name": "test_game", "n_players": 4})

        assert res.status_code == 200
        assert type(res.json()["game_token"]) == str
        self.game_token = res.json()["game_token"]
        self.game_ids += [res.json()["game_id"]]

    def test_join_game(self):
        for i, client in enumerate(self.clients[1:]):

            res = client.post(f"v1/games/{self.game_ids[0]}/join")
            assert res.status_code == 200, res.json()

    def test_request_get_game_list(self):
        res = self.clients[0].get("v1/games")

        assert res.status_code == 200
        assert len(res.json()) == 1
        for idx, game_id in enumerate(self.game_ids):
            assert game_id == res.json()[idx]["game_id"]

    def test_get_individual_game_data(self):
        print(self.game_ids)
        res = self.clients[0].get(
            f"v1/games/{self.game_ids[0]}", json=self.players[0])
        assert res.status_code == 200

        assert res.json()["game_id"] == self.game_ids[0]
        assert len(res.json()["players"]) == len(res.json()["order"])
        assert res.json()["active_player_index"] == 0

    def test_change_team(self):
        res = self.clients[0].get(
            f"v1/games/{self.game_ids[0]}", json=self.players[0])

        old_order = res.json()["order"]

        res = self.clients[2].post(
            f"v1/games/{self.game_ids[0]}/player_position",
            json=1,
        )
        print(res.json())
        assert res.status_code == 200
        assert res.json()["order"] == [old_order[0],
                                       old_order[2], old_order[1], old_order[3]]

        # reset the game order
        res = self.clients[1].post(
            f"v1/games/{self.game_ids[0]}/player_position",
            json=1,
        )

        assert res.status_code == 200
        assert res.json()["order"] == old_order

    def test_start_game_and_check_cards(self):
        res = self.clients[0].post(f"v1/games/{self.game_ids[0]}/start")

        assert res.status_code == 200

        players = res.json()["player_list"]

        for i in range(4):
            for j in range(4):
                # the j-th marble of the i-th player should have the position below
                marble_j = players[i]["marbles"][j]
                assert marble_j["position"] == -i * 4 - j - 1

        res = self.clients[0].get(
            f"v1/games/{self.game_ids[0]}/cards",
        )
        assert res.status_code == 200

        print(res.json())
        assert res.json()["hand"][0]["uid"] == 99
        self.cards.append(res.json()["hand"])

        for i in range(1, 4):
            res = self.clients[i].get(f"v1/games/{self.game_ids[0]}/cards")
            assert res.status_code == 200

            self.cards.append(res.json()["hand"])

    def test_swap_cards(self):
        res = self.clients[0].post(
            f"v1/games/{self.game_ids[0]}/swap_cards", json=self.cards[0][0]
        )
        assert res.status_code == 200

        for i in range(1, 4):
            res = self.clients[i].post(
                f"v1/games/{self.game_ids[0]}/swap_cards", json=self.cards[i][0]
            )
            assert res.status_code == 200

        for i in range(4):
            res = self.clients[i].get(f"v1/games/{self.game_ids[0]}/cards")
            assert res.status_code == 200
            self.cards[i] = res.json()["hand"]
            assert len(self.cards[i]) == 6

        assert any([card["uid"] == 99 for card in self.cards[2]])


import torch
from transformers import pipeline, Pipeline, AutoTokenizer, AutoModelForSeq2SeqLM
from tqdm import tqdm
from srt import Subtitle

from engine.engine import Engine

class NllbEngine(Engine):
    translator: Pipeline

    def __init__(self, c) -> None:
        ec = c.engine.engine_configs
        tokenizer = AutoTokenizer.from_pretrained(ec["model"])
        model = AutoModelForSeq2SeqLM.from_pretrained(ec["model"])

        device = -1
        if (torch.cuda.is_available()):
            device = torch.cuda.current_device()

        self.translator = pipeline(
            "translation",
            device=device,
            model=model,
            tokenizer=tokenizer,
            src_lang=ec["srcLang"],
            tgt_lang=ec["tgtLang"],
            max_length=ec["maxLength"]
        )

    def Translate(self, query:str) -> str:
        return self.translator(query)[0]["translation_text"] # type: ignore

    def TranslateList(self, queries: list[Subtitle]) -> list[Subtitle]:
        st_idx = 0
        res = queries.copy()
        stream = (sub.content for sub in queries)

        for result in tqdm(self.translator(stream, batch_size=1), total=len(queries)):
            #if (type(result) is list):
            #    translated = result[0]["translation_text"]
            #    res[st_idx].content = translated
            #    st_idx += 1
            translated = result[0]["translation_text"] # type: ignore
            res[st_idx].content = translated
            st_idx += 1
        return res


# URL for login into booking room
uoBookRoomUrl = 'https://bibliorooms.uottawa.ca/'

boundBoxPixelOffset = 40

'''
    text indicator which is actually the status of
    the current timeSlot it is used by setTextAdd()
    to set the correct text when visualising the result on the calendar image

    It is also a great way to tell the status of the timeslot on the console
'''

FIRST_HALF_INDICATOR = 'FIRST-HALF-FREE'
SECOND_HALF_INDICATOR = 'SECOND-HALF-FREE'
FULLY_RESERVABLE_INDICATOR = 'FREE'
FULLY_BOOK_INDICATOR = 'FULL'
CLOSED_INDICATOR = 'CLOSE'

FIRST_HALF_FULL_SECOND_HALF_CLOSE_INDICATOR = 'FIRST_HALF_FULL_SECOND_HALF_CLOSE'
FIRST_HALF_FREE_SECOND_HALF_CLOSE_INDICATOR = 'FIRST_HALF_FREE_SECOND_HALF_CLOSE'

FIRST_HALF_CLOSE_SECOND_HALF_FULL_INDICATOR = 'FIRST_HALF_FREE_SECOND_HALF_FULL'
FIRST_HALF_CLOSE_SECOND_HALF_FREE_INDICATOR = 'FIRST_HALF_CLOSE_SECOND_HALF_FREE'

'''
    Text indicator used in when adding text
    to the availability img
'''

TEXT_FREE = 'FREE'
TEXT_FULL = 'FULL'
TEXT_FIRST_HALF = 'Ffree'
TEXT_SECOND_HALF = 'Sfree'
TEXT_CLOSE = 'CLOS'
TEXT_FIRST_HALF_FREE_SECOND_HALF_CLOSE = 'Ff SC'
TEXT_FIRST_HALF_FULL_SECOND_HALF_CLOSE = 'FF SC'
TEXT_FIRST_HALF_CLOSE_SECOND_HALF_FREE = 'FC Sf'
TEXT_FIRST_HALF_CLOSE_SECOND_HALF_FULL = 'FC SF'
TEXT_UNDEFINED = 'UND'

'''
    Portion divisor used when portioning the image
    when searching by area
'''

PORTION_HEIGHT_DIVISOR = 2
PORTION_WIDTH_DIVISOR = 2

'''
    Corrector used when initial portioning did not find the date
    It will get added to the initial potion divisor

    For ex:
     PORTION_HEIGHT_DIVISOR += PORTION_HEIGHT_CORRECTOR = 2
'''

PORTION_HEIGHT_CORRECTOR = 2
PORTION_WIDTH_CORRECTOR = 2

'''
    Number of maximum narrow search loop iterations to find the
    date in the calendar image

    In combination to the portion divisor and the portion corrector
    it will reduce the size of the area searched by the algorithm
'''

NARROW_SEARCH_MAX_ITERATION = 3

'''
    constants rgb values representing the color
    of the portion of the image representing by closed indicator

    It is a range because the actual value is not always the same since
    the image portioning is random
'''

CLOSED_IMAGE_RED_MAX_VALUE = 220
CLOSED_IMAGE_RED_MIN_VALUE = 120

CLOSED_IMAGE_GREEN_MAX_VALUE = 200
CLOSED_IMAGE_GREEN_MIN_VALUE = 110

CLOSED_IMAGE_BLUE_MAX_VALUE = 200
CLOSED_IMAGE_BLUE_MIN_VALUE = 110


# coding: utf-8
from typing import List
from dataclasses import asdict
from .sql_ctx import SqlCtx
from .base_sql_table import BaseSqlTable
from ..data_class.module_info import ModuleInfo

class TblModuleInfo(BaseSqlTable):
    def __init__(self, connect_str: str) -> None:
        super().__init__(connect_str=connect_str)

    def get_table_name(self) -> str:
        """Gets the current table name"""
        return 'module_info'

    def insert(self, data: List[ModuleInfo]) -> None:
        """
        Inserts/updates data. Handles inserting and updating

        Args:
            data (List[ModuleInfo]): data to update
        """
        if len(data) == 0:
            return
        values = [asdict(itm) for itm in data]
        with SqlCtx(self.conn_str) as db:
            query = """INSERT INTO module_info
            VALUES (:id_module_info, :url_base, :file)
            ON CONFLICT(id_module_info)
            DO UPDATE SET url_base=excluded.url_base, file=excluded.file;
            """
            with db.connection:
                db.cursor.executemany(query, values)

    def update(self, data: List[ModuleInfo]) -> None:
        """
        Updates data. Handles updating

        Args:
            data (List[ModuleInfo]): data to update
        """
        self.insert(data)


from lxml import etree

html = etree.parse('./s20.html')

rsp = html.xpath("/bookstore/book")

print(rsp)

rst = html.xpath("//book[@category='sport']/year ")
#因为上面解析的rst是一个list，下面这一步将数据从list里面拿出来，重新放到rst里面
rst = rst[0]
print(rst.tag)
print(rst.text)


from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import QPixmap
from PIL import Image
import numpy as np
from commonInterface import *
import findVessels

def runInterface(data):
    app = QApplication([]);
    window = QWidget();

    inter = interface(data);
    window.setLayout(inter.layout);
    window.resize(1480, 720)

    window.show();
    app.exec_();
    return inter.segmentedData;

class interface:
    def __init__(self, data):
        # Current coords
        self.z = 0;
        self.imagesLoaded = 300
        self.data = np.array(data, np.uint16);
        self.edgeMap = np.array(data, np.uint16);
        self.segmentedData = np.array(data);

        # In pyqt widgets must be stacked vertically or horizontally. To achive
        # to achive the desired layout they are stored in larger containers

        ### Basic controls
        # Create widgits
        self.xControl = sliderControl("x", data.shape[0] - 1);
        self.initalThresh = sliderControl("Initial threshold", 255);
        self.finalThresh = sliderControl("Final threshold", 255);

        # Connect widgits
        self.xControl.slider.valueChanged.connect(lambda: self.updateCoords(self.xControl.value));
        self.initalThresh.slider.valueChanged.connect(lambda: self.updateThresholds(self.initalThresh.value, self.finalThresh.value));
        self.finalThresh.slider.valueChanged.connect(lambda: self.updateThresholds(self.initalThresh.value, self.finalThresh.value));

        # Create layout
        self.basicControls = QVBoxLayout();
        self.basicControls.addLayout(self.xControl.layout);
        self.basicControls.addLayout(self.initalThresh.layout);
        self.basicControls.addLayout(self.finalThresh.layout);

        ### Erosion iteration controls (for opencv's fastNlMeansDenoising)
        # Create widgets
        self.kernelSize = labeledEdit("Kernel size");
        self.cannyHiThresh = labeledEdit("Canny edge detection high threshold")
        self.cannyLoThresh = labeledEdit("Canny edge detect low threshold");
        self.erosionCount = labeledEdit("Number of erosion steps")
        self.contourLengthThresh = labeledEdit("Min contour length");
        self.iterations = labeledEdit("Number of iterations");
        self.segmentButton = QPushButton("Segment data");

        #  Connect widgets
        self.segmentButton.clicked.connect(lambda: self.updateEdgeMap( \
        self.kernelSize.getVal(), self.cannyLoThresh.getVal(), self.cannyHiThresh.getVal(), \
        self.erosionCount.getVal(), "Circle", self.iterations.getVal(), \
        self.initalThresh.value, self.finalThresh.value));

        # Create layout
        self.segmentationControls = QVBoxLayout();
        self.segmentationControls.addLayout(self.kernelSize.layout);
        self.segmentationControls.addLayout(self.cannyHiThresh.layout);
        self.segmentationControls.addLayout(self.cannyLoThresh.layout);
        self.segmentationControls.addLayout(self.erosionCount.layout);
        self.segmentationControls.addLayout(self.contourLengthThresh.layout);
        self.segmentationControls.addLayout(self.iterations.layout);
        self.segmentationControls.addWidget(self.segmentButton);

        ### Connect noise filter to saturatoin layout
        self.filterPanel = QHBoxLayout();
        self.filterPanel.addLayout(self.basicControls);
        self.filterPanel.addLayout(self.segmentationControls);

        ### Allow cleaned files to be saved
        # Create widgets
        self.savePathSelect = labeledEdit("Save path");
        self.saveButton = QPushButton("Save");
        self.startPoint = labeledEdit("Start");
        self.endPoint = labeledEdit("End");

        ### Display image
        self.image = QLabel("loop");
        self.pixmap = QPixmap('Flamboyant_Potato.jpg');
        self.image.setPixmap(self.pixmap);

        ### Connect image to control layouts
        self.layout = QVBoxLayout();
        self.layout.addWidget(self.image);
        self.layout.addLayout(self.filterPanel);

    # Updates viewpoint coordinates
    def updateCoords(self, zVal):
        self.z = zVal;
        self.updateImage();

    def updateEdgeMap(self, kernelSize, cannyThreshLo, cannyThreshHi, \
    erosionCount, kernel, iterations, initialThreshold, finalThreshold):
        # Update classes' edgemap
        self.edgeMap = findVessels.generateConfidencemap( \
        self.data, kernelSize, cannyThreshHi, cannyThreshLo, \
        erosionCount, kernel, iterations);
        # Generate new segmented data so image is changed
        self.segmentedData = findVessels.generateSegmentedImage(self.data, self.edgeMap, initialThreshold, finalThreshold);
        self.updateImage();

    def updateThresholds(self, initialThreshold, finalThreshold):
        self.segmentedData = findVessels.generateSegmentedImage(self.data, self.edgeMap, initialThreshold, finalThreshold);
        self.updateImage();

    # Updates the image displayed
    def updateImage(self):
        self.genImage("./", self.z);
        self.pixmap = QPixmap("./workingImg.png");
        self.image.setPixmap(self.pixmap);

    def genImage(self, path, z):
        #try:
        # Create base
        composite = Image.new('RGB', (self.data[z].shape[0]*2, self.data[z].shape[1]))

        # Create images
        originalData = Image.fromarray(self.data[z]);
        originalData = originalData.convert('RGB');
        segmentedLayer = Image.fromarray(self.segmentedData[z]);
        segmentedLayer = segmentedLayer.convert('RGB');
        mask = Image.fromarray(self.segmentedData[z]);
        mask = mask.convert('L');

        # convert segmented layer to red
        matrix = (1.0, 0.0, 0.0, 0.0,   0.0, 0.0, 0.0, 0.0,   0.0, 0.0, 0.0, 0.0);
        segmentedLayer = segmentedLayer.convert('RGB',matrix);

        # paste images together
        composite.paste(originalData, (0, 0));
        composite.paste(originalData, (self.data[z].shape[0], 0));
        composite.paste(segmentedLayer, (self.data[z].shape[0], 0), mask);

        composite.save(path + "workingImg" + ".png");
        #except:
            #print("out of range of images");
            #print(self.data.shape);


# -*- coding: utf-8 -*-
"""
Created on Tue Nov 30 15:19:34 2021

@author: Notebook
"""

class Company:
    def __init__(self):
        # Protected member
        self._project = "NLP"

"""
Analoginya : dasarnya adalah membuat kelas proteksi sehingga bagaimana caranya
    agar dapat dipanggil. Agar dapat dipanggil maka dilakukan pewarisan kelas proteksi
    menjadi public sehingga kelas yg awalnya proteksi dapat diakses semua kelas
"""

                                #ATAU

"""
dideklarasikan dalam kontrukstor kemudian dipanggil pada method yang nantinya
    dipanggil pada intance atau outinstance
"""

# Inheritance dari kelas Proteksi
class Employee(Company):
    def __init__(self, name):
        self.name = name

        Company.__init__(self) # Memanggil konstruktor protected class

    def show(self):
        print("Employee name :", self.name)

        """
        Memanggil atribut property Protected
        """

        print("Working on project :", self._project)

c = Employee("Jessa")
c.show()

print('\n\n\n')
# pemanggilan manual protected data member
print('Project:', c._project)
print('Nama:', c.name)


from graphy.location.tests.conftest import queries

def test_drf_without_select_related_uses_5_calls(drf_client, address):
    # DRF will run query in get_queryset.
    sqls = queries(
        lambda: drf_client.get(f'/location/addresses/{address.id}/')
    )
    assert len(sqls) == 5

def test_drf_with_select_related_uses_1_call(drf_client, address):
    # DRF will run query in get_queryset.
    sqls = queries(
        lambda: drf_client.get(
            f'/location/addresses/{address.id}/?select_related'
        )
    )
    assert len(sqls) == 1

def test_gql_select_everything_uses_5_calls(gql_client, address):
    query = """
      query {
        addresses {
          id
          streetAddress
          country
          latitude
          longitude
          zipCode {
            id
            code
            name
            municipality {
              id
              name
              county {
                id
                name
                code
                country
              }
            }
            county {
              id
              name
              code
              country
            }
          }
        }
      }
    """
    sqls = queries(
        lambda: gql_client.execute(query)
    )
    assert len(sqls) == 5

def test_graphene_fetches_whole_db_object(gql_client, address):
    # Query only requires one field. Graphene will ask for whole object
    query = """
        query($id: UUID!) {
          address(id: $id) {
            id
          }
        }
    """
    params = {'id': str(address.id)}

    sqls = queries(lambda: gql_client.execute(query, variables=params))

    assert len(sqls) == 1
    assert sqls[0].startswith(
        'SELECT "location_address"."id", '
        '"location_address"."created_at", '
        '"location_address"."updated_at", '
        '"location_address"."street_address", '
        '"location_address"."zip_code_id", '
        '"location_address"."country", '
        '"location_address"."latitude", '
        '"location_address"."longitude" FROM '
    )

def test_graphene_does_not_utilize_select_related(gql_client, address):
    # Graphene will not attempt to use .select- or .prefetch_related.
    query = """
        query($id: UUID!) {
          address(id: $id) {
            id
            country
            streetAddress
            latitude
            longitude
            zipCode {
              id
              code
              name
            }
          }
        }
    """
    params = {'id': str(address.id)}

    sqls = queries(lambda: gql_client.execute(query, variables=params))
    assert len(sqls) == 2

def test_graphene_fethes_fk_object_even_if_we_only_need_id(
    gql_client, address
):
    # zipCode.id is available on address.zip_code_id, so 1 query is sufficient.
    # Graphene will still do an extra call for retrieving zip code instance.
    query = """
        query($id: UUID!) {
          address(id: $id) {
            id
            zipCode {
              id
            }
          }
        }
    """
    params = {'id': str(address.id)}

    sqls = queries(lambda: gql_client.execute(query, variables=params))
    assert len(sqls) == 2


from datetime import datetime
from urllib.parse import urljoin
from uuid import UUID

from fastapi import APIRouter, Depends, Path
from fastapi.exceptions import HTTPException

from ... import models, schemas
from ...crud import CRUD
from .utils import get_textures_url

router = APIRouter(tags=["User information"])

async def resolve_user(user_id: UUID = Path(), crud: CRUD = Depends()):
    return await crud.get_user_by_uuid(user_id)

@router.get("/user/{user_id}", response_model=schemas.UserTextures)
async def get_user_textures_by_uuid(
    user: models.User | None = Depends(resolve_user),
    at: datetime | None = None,
    crud: CRUD = Depends(),
    textures_url: str = Depends(get_textures_url),
) -> schemas.UserTextures:
    """Get the currently logged in user information."""
    if user is None:
        raise HTTPException(404)
    return await get_user_textures(user, at, crud, textures_url)

async def get_user_textures(
    user: models.User,
    at: datetime | None,
    crud: CRUD,
    textures_url: str,
):
    textures = await crud.get_user_textures(user, at=at)
    return schemas.UserTextures(
        profile_id=user.uuid,  # type: ignore
        profile_name=user.name,  # type: ignore
        textures={
            k: schemas.Texture(
                url=urljoin(textures_url, v.upload.hash),
                metadata=v.meta,
            )
            for k, v in textures.items()
        },
    )


import os
import sys

import pandas as pd
import numpy as np
import datetime as dt

import sqlalchemy
from sqlalchemy.ext.automap import automap_base
from sqlalchemy.orm import Session
from sqlalchemy import create_engine, inspect

from flask import Flask, jsonify, render_template
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

#################################################
# Database Setup
#################################################

engine = create_engine("sqlite:///db/summaryTables.sqlite")

# reflect an existing database into a new model
Base = automap_base()
# reflect the tables
Base.prepare(engine, reflect=True)

# Save reference to the table
# Samples_Metadata = Base.classes.sample_metadata
print(Base.classes.keys(), file=sys.stderr)
statecount = Base.classes.statecount
wordcloud = Base.classes.wordcloud
yearName = Base.classes.yearName

# Create our session (link) from Python to the DB
session = Session(engine)

@app.route("/")
def index():
    """Return the homepage."""
    return render_template("index.html", statecount=statecount, wordcloud=wordcloud)

@app.route("/cloudchartdata")
def cloudchartdata():
    """Return the MetaData for a given sample."""
    sel = [
        wordcloud.Name,
        wordcloud.total_count,
    ]

    results = session.query(*sel).all()
    print(results)
    # Create a dictionary entry for each row of metadata information
    top50 = {}
    for result in results:
        top50["Name"] = result[0]
        top50["total_count"] = result[1]

    print(top50)
    return jsonify(results)

@app.route("/cloudchartdata2")
def cloudchartdata2():

    stmt = session.query(wordcloud).statement
    df = pd.read_sql_query(stmt, session.bind)

    data = df.to_json(orient='records')
    return jsonify(data)

@app.route("/linechart/<userSelection>")
def linechart(userSelection):

    stmt = session.query(yearName).statement
    df = pd.read_sql_query(stmt, session.bind)

    # Filter the data based on the sample number and
    # only keep rows with values above 1
    print(df)
    sample_data = df[df.Name.str.lower() == userSelection]
    print(sample_data)
    print(userSelection)
    data = sample_data.to_json(orient='records')
    return data

@app.route("/chlorodata")
def chlorodata():

    stmt = session.query(statecount).statement
    df = pd.read_sql_query(stmt, session.bind)

    data = df.to_json(orient='records')
    return jsonify(data)

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


from .base_linked_list import BaseLinkedList
from .node import Node

class LinkedList(BaseLinkedList):
    def __init__(self):
        super(LinkedList, self).__init__()

    def add(self, data: Node):
        if not isinstance(data, Node):
            raise TypeError()

        if self.node is None:
            self.node: Node = data
        else:
            current = self.node
            while current.next is not None:
                current = current.next
            current.next = data
        self.length += 1

    @classmethod
    def create(cls, node: Node) -> 'LinkedList':
        linked_list = LinkedList()
        if node is None:
            return linked_list
        current = node
        while current is not None:
            linked_list.add(Node(current.data))
            current = current.next
        return linked_list


import unittest

from src.chip8interpreter import Chip8Interpreter

class Chip8InterpreterTest(unittest.TestCase):
    def test_index_default_value(self):
        interpreter = Chip8Interpreter(b'')
        self.assertEqual(interpreter.I, 0)

    def test_store_address_in_index(self):
        interpreter = Chip8Interpreter(b'\xA2\xB4')
        interpreter.step()
        self.assertEqual(interpreter.I, 0x2b4)

    def test_execute_one_instruction_of_two(self):
        # 0000: I := 0x17
        # 0002: I := 0x53
        interpreter = Chip8Interpreter(b'\xA0\x17\xA0\x53')
        interpreter.step()
        self.assertEqual(interpreter.I, 0x17)

    def test_execute_two_instructions(self):
        # 0000: I := 0x17
        # 0002: I := 0x53
        interpreter = Chip8Interpreter(b'\xA0\x17\xA0\x53')
        interpreter.step()
        interpreter.step()
        self.assertEqual(interpreter.I, 0x53)

    def test_execute_two_instructions_with_jump(self):
        # 0000: JUMP 0x4
        # 0002: I := 17
        # 0004: I := 53
        interpreter = Chip8Interpreter(b'\x10\x04\xA0\x17\xA0\x53')
        interpreter.step()
        interpreter.step()
        self.assertEqual(interpreter.I, 0x53)

    def test_register_out_of_bounds_raises_error(self):
        interpreter = Chip8Interpreter(b'')

        with self.assertRaises(IndexError) as error:
            interpreter.get_register(16)

    def test_register_out_of_negative_bounds_raises_error(self):
        interpreter = Chip8Interpreter(b'')

        with self.assertRaises(IndexError) as error:
            interpreter.get_register(-1)

    def test_default_registers(self):
        interpreter = Chip8Interpreter(b'')
        # Test registers between 0 and 15 (in hexa)
        for i in range(0, 0xf):
            self.assertEqual(interpreter.get_register(i), 0)

    def test_graphic_memory_initialization(self):
        interpreter = Chip8Interpreter(b'')
        self.assertEqual(interpreter.get_pixel(0, 0), 0)
        self.assertEqual(interpreter.get_pixel(63, 31), 0)

    def test_graphic_memory_put_pixel(self):
        interpreter = Chip8Interpreter(b'')
        interpreter.put_pixel(42, 17, 1)
        self.assertEqual(interpreter.get_pixel(42, 17), 1)

    def test_graphic_memory_out_of_bounds(self):
        interpreter = Chip8Interpreter(b'')

        with self.assertRaises(IndexError) as error:
            interpreter.get_pixel(64, 31)

        with self.assertRaises(IndexError) as error:
            interpreter.get_pixel(63, 32)

        with self.assertRaises(IndexError) as error:
            interpreter.get_pixel(-1, 17)

        with self.assertRaises(IndexError) as error:
            interpreter.get_pixel(17, -1)

    def test_execute_sprite(self):
        # 0000: sprite v0 v0 1 (I implicitly gives the sprite address)
        interpreter = Chip8Interpreter(b'\xD0\x01\x12')
        # Force the Index register to point to the byte 2
        # The byte 2 contains the sprite to draw
        interpreter.I = 2
        interpreter.step()

        # The drawn sprite should look like: 00010010
        # Each element is a pixel turned on
        self.assertPixelLine(interpreter, 0, 0, "00010010")

    def test_execute_two_tall_sprite(self):
        # 0000: sprite v0 v0 2 (I implicitly gives the sprite address)
        interpreter = Chip8Interpreter(b'\xD0\x02\x12\x34')
        # Force the Index register to point to the byte 2
        # The byte 2 contains the sprite to draw
        interpreter.I = 2
        interpreter.step()

        # The drawn sprite should look like:
        #   00010010
        #   00110100
        # Each element is a pixel turned on
        self.assertPixelLine(interpreter, 0, 0, "00010010")
        self.assertPixelLine(interpreter, 0, 1, "00110100")

    def assertPixelLine(self, interpreter, x, y, expected_pattern):
        got_pattern = ""
        for i in range(x, x + 8):
            got_pattern += str(interpreter.get_pixel(i, y))
        self.assertEqual(expected_pattern, got_pattern)