import os
import sys
import traceback
import configparser
import requests
import keyboard
import tkinter
import tkinter.ttk
import tkinter.filedialog
import tkinter.messagebox
import PIL.Image
import PIL.ImageTk
import lib.sheets_client
import lib.igdb_client
import lib.thegamesdb_client
import lib.utils
import lib.canvas_cover
import time

class MainFrame(tkinter.Frame):
	TOKENS_FILENAME = "tokens.ini"
	RESIZED_COVER_FILE_NAME = "cover.png"
	SCRAPER_COVER_FILE_NAME = "scraper_cover.png"

	def __init__(self, window, **kwargs):
		tkinter.Frame.__init__(self, window, **kwargs)

		self.window = window

		self.model = None

		self.timer_id = None

		self.config = configparser.ConfigParser()
		self.config.read("config.ini")

		self.utils = lib.utils.Utils()

		self.pack(expand = tkinter.YES, fill = tkinter.BOTH)

		menu_bar = tkinter.Menu(self.window)
		file_menu = tkinter.Menu(menu_bar, tearoff = 0)
		file_menu.add_command(label = "Open", command = self.on_menu_file_open)
		file_menu.add_command(label = "Save", command = self.on_menu_file_save)
		menu_bar.add_cascade(label = "File", menu = file_menu)

		self.window.config(menu = menu_bar)

		frame_left = tkinter.Frame(self, width = 300)
		frame_left.pack_propagate(False)
		frame_left.pack(side = tkinter.LEFT, fill = tkinter.BOTH)

		frame_right = tkinter.Frame(self, width = 300)
		frame_right.pack_propagate(False)
		frame_right.pack(side = tkinter.RIGHT, fill = tkinter.BOTH)

		frame_cover = tkinter.LabelFrame(self, text = "Jaquette")
		frame_cover.pack(side = tkinter.RIGHT, expand = tkinter.YES, fill = tkinter.BOTH, padx = 5, pady = 5)

		frame_logo = tkinter.Frame(frame_right)
		frame_logo.pack(side = tkinter.BOTTOM, fill = tkinter.BOTH)

		frame_sheet = tkinter.LabelFrame(frame_left, text = "Gdoc")
		frame_sheet.pack(side = tkinter.TOP, fill = tkinter.BOTH, padx = 5, pady = 5)

		frame_sheet_top = tkinter.Frame(frame_sheet)
		frame_sheet_top.pack(side = tkinter.TOP, fill = tkinter.BOTH)

		frame_sheet_bottom = tkinter.Frame(frame_sheet)
		frame_sheet_bottom.pack(side = tkinter.BOTTOM, fill = tkinter.BOTH)

		frame_run = tkinter.LabelFrame(frame_left, text = "Run")
		frame_run.pack(side = tkinter.TOP, fill = tkinter.BOTH, padx = 5, pady = 5)

		frame_run_top = tkinter.Frame(frame_run)
		frame_run_top.pack(side = tkinter.TOP, fill = tkinter.BOTH)

		frame_run_bottom = tkinter.Frame(frame_run)
		frame_run_bottom.pack(side = tkinter.BOTTOM, fill = tkinter.BOTH)

		frame_sheet_labels = tkinter.Frame(frame_sheet_top)
		frame_sheet_labels.pack(side = tkinter.LEFT, fill = tkinter.BOTH)

		frame_sheet_values = tkinter.Frame(frame_sheet_top)
		frame_sheet_values.pack(side = tkinter.RIGHT, expand = tkinter.YES, fill = tkinter.BOTH)

		frame_run_labels = tkinter.Frame(frame_run_top)
		frame_run_labels.pack(side = tkinter.LEFT, fill = tkinter.BOTH)

		frame_run_values = tkinter.Frame(frame_run_top)
		frame_run_values.pack(side = tkinter.RIGHT, expand = tkinter.YES, fill = tkinter.BOTH)

		frame_scraper_game_info = tkinter.LabelFrame(frame_right, text = "Informations jeu")
		frame_scraper_game_info.pack(side = tkinter.TOP, fill = tkinter.BOTH, padx = 5, pady = 5)

		frame_scraper_game_info_top = tkinter.Frame(frame_scraper_game_info)
		frame_scraper_game_info_top.pack(side = tkinter.TOP, fill = tkinter.BOTH)

		frame_scraper_game_info_top_labels = tkinter.Frame(frame_scraper_game_info_top)
		frame_scraper_game_info_top_labels.pack(side = tkinter.LEFT, fill = tkinter.BOTH)

		frame_scraper_game_info_top_values = tkinter.Frame(frame_scraper_game_info_top)
		frame_scraper_game_info_top_values.pack(side = tkinter.RIGHT, expand = tkinter.YES, fill = tkinter.BOTH)

		frame_scraper_game_info_bottom = tkinter.Frame(frame_scraper_game_info)
		frame_scraper_game_info_bottom.pack(side = tkinter.BOTTOM, fill = tkinter.BOTH)

		frame_scraper_game_info_canvas = tkinter.Frame(frame_scraper_game_info)
		frame_scraper_game_info_canvas.pack(side = tkinter.BOTTOM, fill = tkinter.BOTH)

		pil_img = PIL.Image.open("resources/retrolection.png")
		self.img_logo = PIL.ImageTk.PhotoImage(pil_img) # reference to image must be kept to avoid garbage deletion
		canvas = tkinter.Canvas(frame_logo, width = self.img_logo.width(), height = self.img_logo.height())
		canvas.create_image((0, 0), anchor = tkinter.NW, image = self.img_logo)
		canvas.pack(side = tkinter.RIGHT)

		self.combo_consoles = self.create_combo(frame_sheet_labels, frame_sheet_values, "Supports: ", self.on_combo_consoles_changed)
		self.entry_support_suffix = self.create_entry(frame_sheet_labels, frame_sheet_values, "Suffixe support: ")
		self.combo_games = self.create_combo(frame_sheet_labels, frame_sheet_values, "Jeux: ", self.on_combo_games_changed)
		self.entry_game_suffix = self.create_entry(frame_sheet_labels, frame_sheet_values, "Suffixe nom du jeu: ")
		self.label_progression_console = self.create_label(frame_sheet_labels, frame_sheet_values, "Progression console: ")
		self.label_progression_total = self.create_label(frame_sheet_labels, frame_sheet_values, "Progression totale: ")
		self.label_viewer_sub = self.create_label(frame_sheet_labels, frame_sheet_values, "Viewer sub: ")
		self.entry_viewer_sub_suffix = self.create_entry(frame_sheet_labels, frame_sheet_values, "Suffixe viewer sub: ")
		self.label_viewer_don = self.create_label(frame_sheet_labels, frame_sheet_values, "Viewer don: ")
		self.entry_viewer_don_suffix = self.create_entry(frame_sheet_labels, frame_sheet_values, "Suffixe viewer don: ")
		self.label_challenge_sub = self.create_label(frame_sheet_labels, frame_sheet_values, "Défi sub: ")
		self.entry_challenge_sub_suffix = self.create_entry(frame_sheet_labels, frame_sheet_values, "Suffixe défi sub: ")
		self.label_challenge_don = self.create_label(frame_sheet_labels, frame_sheet_values, "Défi don: ")
		self.entry_challenge_don_suffix = self.create_entry(frame_sheet_labels, frame_sheet_values, "Suffixe défi don: ")
		self.create_button(frame_sheet_bottom, "Recharger Gdoc", self.on_reload_sheet_click)
		self.create_button(frame_sheet_bottom, "Envoyer vers OBS", self.on_send_to_obs_click)
		self.label_status = self.create_label(frame_run_labels, frame_run_values, "Statut: ")
		self.label_timer_game = self.create_label(frame_run_labels, frame_run_values, "Temps: ")
		self.label_timer_support = self.create_label(frame_run_labels, frame_run_values, "Temps support: ")
		self.label_timer_total = self.create_label(frame_run_labels, frame_run_values, "Total Retrolection: ")
		self.button_start_pause = self.create_button(frame_run_bottom, "Démarrer", self.on_start_pause_click)
		self.create_button(frame_run_bottom, "Remettre à zéro", self.on_reset_click)
		self.create_button(frame_run_bottom, "Valider", self.on_validate_click)
		self.create_button(frame_cover, "Charger...", self.on_cover_load_click)

		self.canvas_cover = lib.canvas_cover.CanvasCover(frame_cover)

		self.combo_scraper_games = self.create_combo(frame_scraper_game_info_top_labels, frame_scraper_game_info_top_values, "Titre trouvés: ", self.on_combo_scraper_games_changed)
		self.label_scraper_game_release_date = self.create_label(frame_scraper_game_info_top_labels, frame_scraper_game_info_top_values, "Date de sortie: ")
		self.label_scraper_game_modes = self.create_label(frame_scraper_game_info_top_labels, frame_scraper_game_info_top_values, "Modes: ")
		self.label_scraper_game_alternates = self.create_label(frame_scraper_game_info_top_labels, frame_scraper_game_info_top_values, "Titre(s) alternatif(s): ")

		label = tkinter.Label(frame_scraper_game_info_top_labels, anchor = tkinter.W, text = "Jaquette: ")
		label.pack(anchor = tkinter.W)

		self.canvas_scraper_cover = lib.canvas_cover.CanvasCover(frame_scraper_game_info_canvas)

		self.create_button(frame_scraper_game_info_bottom, "<< Utiliser cette jaquette", self.on_use_this_cover_click)
		self.create_button(frame_scraper_game_info_bottom, "Sauvegarder cette jaquette", self.on_save_this_cover_click)

		keyboard.add_hotkey(self.config["HOTKEYS"]["HOTKEY_START_PAUSE"], lambda: window.after(1, self.on_start_pause_click))

	def create_combo(self, frame_label, frame_value, text, on_changed_cb):
		label = tkinter.Label(frame_label, anchor = tkinter.W, text = text)
		label.pack(anchor = tkinter.W, padx = 2, pady = 2)
		combo = tkinter.ttk.Combobox(frame_value, state = "readonly")
		combo.pack(padx = 2, pady = 2, fill = tkinter.X)
		combo.bind("<<ComboboxSelected>>", on_changed_cb)
		return combo

	def create_label(self, frame_label, frame_value, text):
		label = tkinter.Label(frame_label, anchor = tkinter.W, text = text)
		label.pack(anchor = tkinter.W, padx = 2, pady = 2)
		label_value = tkinter.Label(frame_value, anchor = tkinter.W)
		label_value.pack(anchor = tkinter.W, padx = 2, pady = 2)
		return label_value

	def create_entry(self, frame_label, frame_value, text):
		label = tkinter.Label(frame_label, anchor = tkinter.W, text = text)
		label.pack(anchor = tkinter.W, padx = 2, pady = 2)
		entry = tkinter.Entry(frame_value)
		entry.pack(fill = tkinter.X, padx = 2, pady = 3)
		return entry

	def create_button(self, frame, text, on_click_cb):
		button = tkinter.Button(frame, relief = tkinter.GROOVE, text = text, command = on_click_cb)
		button.pack(fill = tkinter.X, padx = 2, pady = 2)
		return button

	def get_combo_value(self, combo):
		current_index = combo.current()
		values = combo.cget("values")
		if current_index >= 0 and current_index < len(values):
			return values[current_index]
		return ""

	def select_combo_value(self, combo, value):
		values = combo.cget("values")

		i = 0
		for v in values:
			if v == value:
				combo.current(i)
				return True
			i += 1

		return False

	def on_menu_file_open(self):
		file_name = tkinter.filedialog.askopenfilename(defaultextension = "*.rcx", filetypes = [("Retrolection context files", "*.rcx")])
		if len(file_name) >= 1:
			self.load_context(file_name)

	def on_menu_file_save(self):
		file_name = tkinter.filedialog.asksaveasfilename(defaultextension = "*.rcx", filetypes = [("Retrolection context files", "*.rcx")])
		if len(file_name) >= 1:
			self.save_context(file_name)

	def on_use_this_cover_click(self):
		if self.canvas_scraper_cover.download_image(MainFrame.SCRAPER_COVER_FILE_NAME):
			self.canvas_cover.load_image(MainFrame.SCRAPER_COVER_FILE_NAME, None, True, MainFrame.RESIZED_COVER_FILE_NAME)

	def on_save_this_cover_click(self):
		file_name = tkinter.filedialog.asksaveasfilename(defaultextension = "*.jpg", filetypes = [("JPEG", "*.jpg")])
		if len(file_name) >= 1:
			self.canvas_scraper_cover.download_image(file_name)

	def on_cover_load_click(self):
		file_name = tkinter.filedialog.askopenfilename()
		self.canvas_cover.load_image(file_name, None, True, MainFrame.RESIZED_COVER_FILE_NAME)
		self.on_send_to_obs_click()

	def set_game_model_value(self, value_label, value):
		model_games = self.model["consoles"][self.model["current_console"]]["games"]
		model_games[self.model["current_game_index"]][value_label] = value

	def set_time(self, time_str):
		self.set_game_model_value("timer", time_str)
		self.label_timer_game.config(text = time_str)
		self.utils.write_file("w", "text-files/timer-game.txt", time_str)

	def set_time_support(self, time_str):
		self.model["consoles"][self.model["current_console"]]["timer_total"] = time_str
		self.label_timer_support.config(text = time_str)
		self.utils.write_file("w", "text-files/timer-support.txt", time_str)

	def set_total_time(self, time_str):
		self.model["timer_total"] = time_str
		self.label_timer_total.config(text = time_str)
		self.utils.write_file("w", "text-files/timer-total.txt", time_str)

	def set_progression_total(self, value):
		self.model["progression_total"] = value
		self.label_progression_total.config(text = value)
		self.utils.write_file("w", "text-files/progression-total.txt", value)

	def set_progression(self, value):
		self.model["consoles"][self.model["current_console"]]["progression"] = value
		self.label_progression_console.config(text = value)
		self.utils.write_file("w", "text-files/progression-console.txt", value)

	def start_timer(self):
		if self.timer_id:
			self.window.after_cancel(self.timer_id)
		self.timer_id = self.window.after(1000, self.update_timer)

	def stop_timer(self):
		if self.timer_id:
			self.window.after_cancel(self.timer_id)
			self.timer_id = None
			return True

		return False

	def on_reload_sheet_click(self):
		self.pause_run(True)
		self.reload_sheet()

	def on_send_to_obs_click(self):
		self.utils.write_file("w", "text-files/support.txt", self.combo_consoles.cget("values")[self.combo_consoles.current()] + self.entry_support_suffix.get())
		self.utils.write_file("w", "text-files/game.txt", self.combo_games.cget("values")[self.combo_games.current()] + self.entry_game_suffix.get())
		self.utils.write_file("w", "text-files/progression-console.txt", self.label_progression_console.cget("text"))
		self.utils.write_file("w", "text-files/progression-total.txt", self.label_progression_total.cget("text"))
		self.utils.write_file("w", "text-files/viewer-sub.txt", self.label_viewer_sub.cget("text") + self.entry_viewer_sub_suffix.get())
		self.utils.write_file("w", "text-files/viewer-don.txt", self.label_viewer_don.cget("text") + self.entry_viewer_don_suffix.get())
		self.utils.write_file("w", "text-files/challenge-sub.txt", self.label_challenge_sub.cget("text") + self.entry_challenge_sub_suffix.get())
		self.utils.write_file("w", "text-files/challenge-don.txt", self.label_challenge_don.cget("text") + self.entry_challenge_don_suffix.get())
		self.utils.write_file("w", "text-files/timer-game.txt", self.label_timer_game.cget("text"))
		self.utils.write_file("w", "text-files/timer-support.txt", self.label_timer_support.cget("text"))
		self.utils.write_file("w", "text-files/timer-total.txt", self.label_timer_total.cget("text"))

		if not self.canvas_cover.has_image():
			self.utils.copy_file("default-cover.png", "img-files/cover.png")
		else:
			self.utils.copy_file(MainFrame.RESIZED_COVER_FILE_NAME, "img-files/cover.png")

	def start_run(self):
		self.button_start_pause.config(text = "Pause")
		self.start_timer()

	def pause_run(self, save_game_to_sheet):
		self.button_start_pause.config(text = "Démarrer")
		# If run in progress
		if self.stop_timer() and save_game_to_sheet:
			self.save_game_to_sheet()

	def on_start_pause_click(self):
		if self.button_start_pause.cget("text") == "Démarrer":
			self.start_run()
		else:
			self.pause_run(True)

	def on_reset_click(self):
		self.pause_run(False)

		model_console = self.model["consoles"][self.model["current_console"]]
		model_game = model_console["games"][self.model["current_game_index"]]

		timer_total_reset_value = self.utils.timeSecToStr(self.utils.timeStrToSec(self.model["timer_total"]) - self.utils.timeStrToSec(model_game["timer"]))
		self.set_total_time(timer_total_reset_value)
		timer_support_reset_value = self.utils.timeSecToStr(self.utils.timeStrToSec(model_console["timer_total"]) - self.utils.timeStrToSec(model_game["timer"]))
		self.set_time_support(timer_total_reset_value)
		self.set_time("00:00:00")

		if model_game["validation_id"] != "":
			value, total = self.utils.progressStrToValues(self.model["progression_total"])
			self.set_progression_total(self.utils.progressValuesToStr(value - 1, total))

			value, total = self.utils.progressStrToValues(model_console["progression"])
			self.set_progression(self.utils.progressValuesToStr(value - 1, total))

			model_game["validation_id"] = ""

		self.update_status()
		self.save_game_to_sheet()

	def on_validate_click(self):
		self.pause_run(False)

		model_console = self.model["consoles"][self.model["current_console"]]
		model_game = model_console["games"][self.model["current_game_index"]]
		if model_game["validation_id"] == "":
			value, total = self.utils.progressStrToValues(self.model["progression_total"])
			self.set_progression_total(self.utils.progressValuesToStr(value + 1, total))

			value, total = self.utils.progressStrToValues(model_console["progression"])
			self.set_progression(self.utils.progressValuesToStr(value + 1, total))

			model_game["validation_id"] = str(value + 1)

			self.update_status()

		self.save_game_to_sheet()

	def save_game_to_sheet(self):
		console = self.model["current_console"]
		model_games = self.model["consoles"][console]["games"]
		current_game_index = self.model["current_game_index"]

		config_sheet = self.config["SHEET"]
		sheet_name = console
		line = str(int(config_sheet["FIRST_GAME_LINE"]) + current_game_index)
		ranges_values = [
			{
				"range": sheet_name + "!" + config_sheet["VALIDATION_COLUMN"] + line + ":" + config_sheet["VALIDATION_COLUMN"] + line,
				"values": [[model_games[current_game_index]["validation_id"]]]
			},
			{
				"range": sheet_name + "!" + config_sheet["TIMER_GAME_COLUMN"] + line + ":" + config_sheet["TIMER_GAME_COLUMN"] + line,
				"values": [[model_games[current_game_index]["timer"]]]
			},
		]

		self.sheets_client.set_values(ranges_values)

	def update_timer(self):
		t = self.utils.timeStrToSec(self.label_timer_game.cget("text"))
		t += 1
		self.set_time(self.utils.timeSecToStr(t))

		t = self.utils.timeStrToSec(self.label_timer_support.cget("text"))
		t += 1
		self.set_time_support(self.utils.timeSecToStr(t))

		t = self.utils.timeStrToSec(self.label_timer_total.cget("text"))
		t += 1
		self.set_total_time(self.utils.timeSecToStr(t))

		self.update_status()

		self.timer_id = self.window.after(1000, self.update_timer)

	def on_combo_consoles_changed(self, event):
		self.process_on_combo_consoles_changed(None)

	def fill_consoles(self, init_values):
		values = []

		for value in self.model["consoles"]:
			values.append(value)

		self.combo_consoles.config(values = values)
		self.combo_consoles.current(0)

		if init_values and ("console" in init_values):
			self.select_combo_value(self.combo_consoles, init_values["console"])

		self.process_on_combo_consoles_changed(init_values)

	def process_on_combo_consoles_changed(self, init_values):
		current_console = self.get_combo_value(self.combo_consoles)
		if current_console != self.model["current_console"]:
			self.model["current_console"] = current_console
			self.fill_games(init_values)
			self.label_progression_console.config(text = self.model["consoles"][current_console]["progression"])
			self.label_timer_support.config(text = self.model["consoles"][current_console]["timer_total"])

	def on_combo_games_changed(self, event):
		self.process_on_combo_games_changed(None)

	def fill_games(self, init_values):
		values = []

		for value in self.model["consoles"][self.model["current_console"]]["games"]:
			values.append(value["name"])

		self.combo_games.config(values = values)
		self.combo_games.current(0)

		if init_values and ("game" in init_values):
			self.select_combo_value(self.combo_games, init_values["game"])

		self.process_on_combo_games_changed(init_values)

	def process_on_combo_games_changed(self, init_values):
		current_game = self.get_combo_value(self.combo_games)

		if current_game != self.model["current_game"]:
			self.pause_run(True)

			self.model["current_game"] = current_game
			current_game_index = self.combo_games.current()
			self.model["current_game_index"] = current_game_index
			model_games = self.model["consoles"][self.model["current_console"]]["games"]

			self.label_viewer_sub.config(text = model_games[current_game_index]["viewer_sub"])
			self.label_viewer_don.config(text = model_games[current_game_index]["viewer_don"])
			self.label_challenge_sub.config(text = model_games[current_game_index]["challenge_sub"])
			self.label_challenge_don.config(text = model_games[current_game_index]["challenge_don"])
			self.label_timer_game.config(text = model_games[current_game_index]["timer"])

			self.update_status()

			self.fill_scraper_games(init_values)
			self.on_send_to_obs_click()

	def update_status(self):
		model_game = self.model["consoles"][self.model["current_console"]]["games"][self.model["current_game_index"]]
		if model_game["validation_id"] != "":
			text = "Fait"
		elif model_game["timer"] != "00:00:00":
			text = "En cours"
		else:
			text = "A faire"

		self.label_status.config(text = text)

	def on_combo_scraper_games_changed(self, event):
		self.process_on_combo_scraper_games_changed(None)

	def fill_scraper_games(self, init_values):
		try:
			if self.game_db_client:
				console = self.model["current_console"]
				game = self.model["current_game"]

				found_games = self.game_db_client.search_game_by_name(game, console)

				self.combo_scraper_games.set("")

				if not found_games:
					self.combo_scraper_games.config(values = [])
				else:
					value_to_id = {}
					values = []

					for v in found_games:
						values.append(v["title"])
						value_to_id[v["title"]] = v["id"]

					self.combo_scraper_games.value_to_id = value_to_id
					self.combo_scraper_games.config(values = values)

					if len(values) >= 1:
						self.combo_scraper_games.current(0)

						if init_values and ("scraper_game" in init_values):
							self.select_combo_value(self.combo_scraper_games, init_values["scraper_game"])

				self.process_on_combo_scraper_games_changed(init_values)

		except Exception as e:
			print("Unexpected error: ", traceback.format_exc())

	def process_on_combo_scraper_games_changed(self, init_values):
		current_scraper_game = self.get_combo_value(self.combo_scraper_games)

		if current_scraper_game != self.model["current_scraper_game"]:
			self.model["current_scraper_game"] = current_scraper_game

			if self.combo_scraper_games.current() < 0:
				self.label_scraper_game_release_date.config(text = "")
				self.label_scraper_game_modes.config(text = "")
				self.label_scraper_game_alternates.config(text = "")
				image_original_path = None
				image_thumb_path = None
			else:
				if self.game_db_client:
					scraper_game = self.combo_scraper_games.cget("values")[self.combo_scraper_games.current()]

					info = self.game_db_client.get_game_info(self.combo_scraper_games.value_to_id[scraper_game])

					self.label_scraper_game_release_date.config(text = info["release_date"])
					self.label_scraper_game_modes.config(text = info["modes"])
					self.label_scraper_game_alternates.config(text = info["alternates"])
					image_original_path = info["url_image"]
					image_thumb_path = info["url_image_thumb"]

			self.canvas_scraper_cover.load_image(image_original_path, image_thumb_path, False, None)

	def set_sheet_data_simple_values_to_model(self, data, model_games, game_start_row, field_name):
		id = data["startRow"] - game_start_row
		if "rowData" not in data:
			return
		for row_data in data["rowData"]:
			if id >= 0 and id < len(model_games):
				if "values" in row_data and "formattedValue" in row_data["values"][0]:
					model_games[id][field_name] = row_data["values"][0]["formattedValue"]
			id += 1

	def set_sheet_data_challenge_values_to_model(self, data, model_games, game_start_row, field_name):
		id = data["startRow"] - game_start_row
		if "rowData" not in data:
			return
		for row_data in data["rowData"]:
			if id >= 0 and id < len(model_games):
				if "values" in row_data:
					values = row_data["values"]

					# Find the first value with a green background color
					for value in values:
						if "formattedValue" in value \
						and "userEnteredFormat" in value \
						and "backgroundColor" in value["userEnteredFormat"]:
							background_color = value["userEnteredFormat"]["backgroundColor"]

							red = 0
							green = 0
							blue = 0
							if "red" in background_color:
								red = background_color["red"];
							if "green" in background_color:
								green = background_color["green"];
							if "blue" in background_color:
								blue = background_color["blue"];

							if red == 0 and green == 1 and blue == 0:
								model_games[id][field_name] = value["formattedValue"]
								break
			id += 1

	def set_sheet_data_simple_value_to_model(self, data, model_console, field_name):
		row_data = data["rowData"][0]
		if "values" in row_data and "formattedValue" in row_data["values"][0]:
			model_console[field_name] = row_data["values"][0]["formattedValue"]

	def set_sheet_data_progression_value_to_model(self, data, model_console, field_name):
		if "rowData" in data:
			row_data = data["rowData"][0]
			if "values" in row_data and "formattedValue" in row_data["values"][0] and "formattedValue" in row_data["values"][2]:
				nb_completed = int(row_data["values"][0]["formattedValue"])
				nb_total = int(row_data["values"][2]["formattedValue"])
				model_console[field_name] = self.utils.progressValuesToStr(nb_completed, nb_total)
				return nb_completed, nb_total

		return 0, 0

	def build_model(self):
		model = {
			"timer_total": "00:00:00",
			"progression_total": "",
			"consoles": {},
			"current_console": "",
			"current_game": "",
			"current_game_index": -1,
			"current_scraper_game": "",
		}

		config_sheet = self.config["SHEET"]

		response = self.sheets_client.get_sheets()

		if response["sheets"]:
			start_index = int(config_sheet["FIRST_GAME_CONSOLE_SHEET"]) - 1
			for i in range(start_index, start_index + int(config_sheet["NUMBER_OF_GAME_CONSOLE_SHEETS"])):
				item = response["sheets"][i];
				if item["properties"] and item["properties"]["title"]:
					model["consoles"][item["properties"]["title"]] = {
						"games": [],
						"progression": "",
						"timer_total": "00:00:00",
					}

		first_line = config_sheet["FIRST_GAME_LINE"]

		ranges = []

		for console in model["consoles"]:
			ranges.append(console + "!" + config_sheet["VALIDATION_COLUMN"] + first_line + ":" + config_sheet["VALIDATION_COLUMN"])
			ranges.append(console + "!" + config_sheet["GAME_NAME_COLUMN"] + first_line + ":" + config_sheet["GAME_NAME_COLUMN"])
			ranges.append(console + "!" + config_sheet["TIMER_GAME_COLUMN"] + first_line + ":" + config_sheet["TIMER_GAME_COLUMN"])
			ranges.append(console + "!" + config_sheet["VIEWER_SUB_COLUMN"] + first_line + ":" + config_sheet["VIEWER_SUB_COLUMN"])
			ranges.append(console + "!" + config_sheet["VIEWER_DON_COLUMN"] + first_line + ":" + config_sheet["VIEWER_DON_COLUMN"])
			ranges.append(console + "!" + config_sheet["CHALLENGE_SUB_COLUMN"] + first_line + ":" + config_sheet["CHALLENGE_SUB_COLUMN"])
			ranges.append(console + "!" + config_sheet["CHALLENGE_DON_FIRST_COLUMN"] + first_line + ":" + config_sheet["CHALLENGE_DON_LAST_COLUMN"])
			ranges.append(console + "!" + config_sheet["PROGRESSION_CELL_RANGE"])
			ranges.append(console + "!" + config_sheet["TIMER_TOTAL_CELL"] + ":" + config_sheet["TIMER_TOTAL_CELL"])

		values = self.sheets_client.get_values(ranges)

		sheets = values["sheets"]

		nb_games_completed = 0
		nb_games_total = 0

		for sheet in sheets:
			console = sheet["properties"]["title"]

			if "data" in sheet:
				data = sheet["data"]

				# Find game column
				game_data = None
				game_start_row = None
				for d in data:
					if "startColumn" in d \
					and d["startColumn"] == self.utils.sheet_a1_value_to_column_number(config_sheet["GAME_NAME_COLUMN"]):
						game_data = d
						game_start_row = d["startRow"]
						break

				for r in game_data["rowData"]:
					if "values" in r \
					and "formattedValue" in r["values"][0]:
						model["consoles"][console]["games"].append({
							"name": r["values"][0]["formattedValue"],
							"validation_id": "",
							"timer": "00:00:00",
							"viewer_sub": "",
							"viewer_don": "",
							"challenge_sub": "",
							"challenge_don": "",
						})

				for d in data:
					if "startColumn" in d:
						column = d["startColumn"]
					else:
						column = 0

					if "startRow" in d:
						row = d["startRow"]
					else:
						row = 0

					if row != 1 and column == self.utils.sheet_a1_value_to_column_number(config_sheet["VALIDATION_COLUMN"]):
						self.set_sheet_data_simple_values_to_model(d, model["consoles"][console]["games"], game_start_row, "validation_id")
					elif column == self.utils.sheet_a1_value_to_column_number(config_sheet["TIMER_GAME_COLUMN"]):
						self.set_sheet_data_simple_values_to_model(d, model["consoles"][console]["games"], game_start_row, "timer")
					elif column == self.utils.sheet_a1_value_to_column_number(config_sheet["VIEWER_SUB_COLUMN"]):
						self.set_sheet_data_simple_values_to_model(d, model["consoles"][console]["games"], game_start_row, "viewer_sub")
					elif column == self.utils.sheet_a1_value_to_column_number(config_sheet["VIEWER_DON_COLUMN"]):
						self.set_sheet_data_simple_values_to_model(d, model["consoles"][console]["games"], game_start_row, "viewer_don")
					elif column == self.utils.sheet_a1_value_to_column_number(config_sheet["CHALLENGE_SUB_COLUMN"]):
						self.set_sheet_data_challenge_values_to_model(d, model["consoles"][console]["games"], game_start_row, "challenge_sub")
					elif column == self.utils.sheet_a1_value_to_column_number(config_sheet["CHALLENGE_DON_FIRST_COLUMN"]):
						self.set_sheet_data_challenge_values_to_model(d, model["consoles"][console]["games"], game_start_row, "challenge_don")
					elif column == self.utils.sheet_a1_value_to_column_number(config_sheet["PROGRESSION_CELL_RANGE"]):
						nb_completed, nb_total = self.set_sheet_data_progression_value_to_model(d, model["consoles"][console], "progression")
						nb_games_completed += nb_completed
						nb_games_total += nb_total
					elif column == self.utils.sheet_a1_value_to_column_number(config_sheet["TIMER_TOTAL_CELL"]):
						self.set_sheet_data_simple_value_to_model(d, model["consoles"][console], "timer_total")

		t = 0
		for console in model["consoles"]:
			t += self.utils.timeStrToSec(model["consoles"][console]["timer_total"])

		model["timer_total"] = self.utils.timeSecToStr(t)

		model["progression_total"] = self.utils.progressValuesToStr(nb_games_completed, nb_games_total)

		return model

	def load(self):
		if not os.path.isfile(MainFrame.TOKENS_FILENAME):
			tkinter.messagebox.showerror("Error", " File "+ MainFrame.TOKENS_FILENAME +" not found. Please run grant_permissions.bat.")
			sys.exit()

		self.game_db_client = None
		if self.config["DATA_BASES"]["GAMES_DB"] == "THEGAMESDB":
			st = time.time()
			self.game_db_client = lib.thegamesdb_client.TheGamesDbClient(self.config["DATA_BASES"]["THEGAMESDB_API_KEY"])
			print(time.time(), "load game_db_client init (ms): ", (time.time() - st) * 1000)
		elif self.config["DATA_BASES"]["GAMES_DB"] == "IGDB":
			st = time.time()
			self.game_db_client = lib.igdb_client.IgdbClient(self.config["DATA_BASES"]["IGDB_API_KEY"])
			print(time.time(), "load igdb_client init (ms): ", (time.time() - st) * 1000)

		st = time.time()
		self.sheets_client = lib.sheets_client.SheetsClient(self.config["SHEET"]["GDOC_API_KEY"], self.config["SHEET"]["OAUTH_CLIENT_ID"], self.config["SHEET"]["OAUTH_CLIENT_SECRET"], self.config["SHEET"]["SPREAD_SHEET_ID"], MainFrame.TOKENS_FILENAME)
		print(time.time(), "load sheets_client init (ms): ", (time.time() - st) * 1000)

		st = time.time()
		self.model = self.build_model()
		print(time.time(), "load build_model (ms): ", (time.time() - st) * 1000)

		self.label_timer_total.config(text = self.model["timer_total"])
		self.label_progression_total.config(text = self.model["progression_total"])

		st = time.time()
		init_values = self.load_context("context.sav")
		print(time.time(), "load load_context (ms): ", (time.time() - st) * 1000)

		self.fill_consoles(init_values)
		st = time.time()
		print(time.time(), "load fill_consoles (ms): ", (time.time() - st) * 1000)

	def reload_sheet(self):
		init_values = {}
		init_values["console"] = self.model["current_console"]
		init_values["game"] = self.model["current_game"]
		init_values["scraper_game"] = self.model["current_scraper_game"]

		self.model = self.build_model()
		self.label_timer_total.config(text = self.model["timer_total"])
		self.label_progression_total.config(text = self.model["progression_total"])
		self.fill_consoles(init_values)

	def load_context(self, file_name):
		init_values = {}
		if os.path.exists(file_name):
			config = configparser.ConfigParser()
			config.read(file_name)

			if "console" in config["CONTEXT"]:
				init_values["console"] = config["CONTEXT"]["console"].replace("<SPACE>", " ")

			if "game" in config["CONTEXT"]:
				init_values["game"] = config["CONTEXT"]["game"].replace("<SPACE>", " ")

			if "scraper_game" in config["CONTEXT"]:
				init_values["scraper_game"] = config["CONTEXT"]["scraper_game"].replace("<SPACE>", " ")

			if "cover" in config["CONTEXT"]:
				self.canvas_cover.load_image(config["CONTEXT"]["cover"], None, True, MainFrame.RESIZED_COVER_FILE_NAME)

			if "support_suffix" in config["CONTEXT"]:
				self.entry_support_suffix.delete(0, tkinter.END)
				self.entry_support_suffix.insert(0, config["CONTEXT"]["support_suffix"].replace("<SPACE>", " "))

			if "game_suffix" in config["CONTEXT"]:
				self.entry_game_suffix.delete(0, tkinter.END)
				self.entry_game_suffix.insert(0, config["CONTEXT"]["game_suffix"].replace("<SPACE>", " "))

			if "challenge_sub_suffix" in config["CONTEXT"]:
				self.entry_challenge_sub_suffix.delete(0, tkinter.END)
				self.entry_challenge_sub_suffix.insert(0, config["CONTEXT"]["challenge_sub_suffix"].replace("<SPACE>", " "))

			if "challenge_don_suffix" in config["CONTEXT"]:
				self.entry_challenge_don_suffix.delete(0, tkinter.END)
				self.entry_challenge_don_suffix.insert(0, config["CONTEXT"]["challenge_don_suffix"].replace("<SPACE>", " "))

			if "viewer_sub_suffix" in config["CONTEXT"]:
				self.entry_viewer_sub_suffix.delete(0, tkinter.END)
				self.entry_viewer_sub_suffix.insert(0, config["CONTEXT"]["viewer_sub_suffix"].replace("<SPACE>", " "))

			if "viewer_don_suffix" in config["CONTEXT"]:
				self.entry_viewer_don_suffix.delete(0, tkinter.END)
				self.entry_viewer_don_suffix.insert(0, config["CONTEXT"]["viewer_don_suffix"].replace("<SPACE>", " "))

		return init_values

	def save_context(self, file_name):
		config = configparser.ConfigParser()

		config["CONTEXT"] = {
			"console": self.model["current_console"].replace(" ", "<SPACE>"),
			"game": self.model["current_game"].replace(" ", "<SPACE>"),
			"support_suffix": self.entry_support_suffix.get().replace(" ", "<SPACE>"),
			"game_suffix": self.entry_game_suffix.get().replace(" ", "<SPACE>"),
			"challenge_sub_suffix": self.entry_challenge_sub_suffix.get().replace(" ", "<SPACE>"),
			"challenge_don_suffix": self.entry_challenge_don_suffix.get().replace(" ", "<SPACE>"),
			"viewer_sub_suffix": self.entry_viewer_sub_suffix.get().replace(" ", "<SPACE>"),
			"viewer_don_suffix": self.entry_viewer_don_suffix.get().replace(" ", "<SPACE>"),
			"scraper_game": self.model["current_scraper_game"].replace(" ", "<SPACE>"),
		}

		image_path = self.canvas_cover.get_image_path()
		if image_path:
			config["CONTEXT"]["cover"] = image_path

		with open(file_name, "w") as f:
			config.write(f)

	def on_close(self):
		self.save_context("context.sav")
		try:
			self.window.destroy()
		except:
			pass

def main():
	window = tkinter.Tk()
	window.title("Retrolection")
	window.geometry("1050x650")
	window.geometry(("+" + str(int((window.winfo_screenwidth() - 1050) / 2)) + "+"+ str(int((window.winfo_screenheight() - (650 + 50)) / 2))))
	f = MainFrame(window)
	window.protocol("WM_DELETE_WINDOW", f.on_close)
	icon = tkinter.PhotoImage(file = "resources/icon.png")
	window.tk.call("wm", "iconphoto", window._w, icon)
	window.after(1, f.load)
	window.mainloop()

class Logger(object):
	def __init__(self, filename = "logs.txt"):
		self.terminal = sys.stdout
		self.log = open(filename, "w")

	def write(self, message):
		self.terminal.write(message)
		self.log.write(message)
		self.log.flush()

	def flush(self):
		self.terminal.flush()
		self.log.flush()

if __name__ == "__main__":
	logger = Logger()
	sys.stdout = logger
	sys.stderr = logger
	main()


from SparseDataset import SparseDataset
from MatrixFactorization import MatrixFactorization
import metrics
import random
import pandas as pd

file_path = './data/ratings.csv'

data = SparseDataset(file_path)

# set n_epochs higher for better prediction
algo = MatrixFactorization(n_epochs=2)

# train model
trainset = data.build_trainset()
algo.fit(trainset)
print('train finished.')
print()

# show factors matrix
pd.set_option('display.max_rows',10)
pd.set_option('display.max_columns',6)
print('Users factorization matrix is:')      # users factorization matrix
print(pd.DataFrame(algo.pu))                    # use pandas for printing purpose only
print()
print('Items factorization matrix is:')      # item factorization matrix
print(pd.DataFrame(algo.qi))
print()

# predict a single score
# algo.predict(192, 302, 4, verbose=True)

# show predicted score and actual score side by side
# randomly choose first 20 records with percentage 20/100000(# of records in total)
print('Randomly choose 1-10 records to compare side by side:')

limit = 10
for uid, iid, r, timestamp in data.raw_ratings:
    if random.random() > limit/100000:
        continue
    if limit == 0:
        break
    algo.predict(uid, iid, r, verbose=True)
    limit -= 1

print()

# show rmse
print('RMSE value of all rated scores is:')

predictions = []
for uid, iid, r, timestamp in data.raw_ratings:
    prediction = (r, algo.predict(uid, iid, r, verbose=False))
    predictions.append(prediction)
metrics.rmse(predictions, verbose=True)


turma = []
while True:
    dados = []
    nome = input('Nome aluno: ')
    nota_1 = float(input("Nota primeiro semestre: "))
    nota_2 = float(input('Nota segundo semestre: '))
    dados.append(f'{nome},{nota_1},{nota_2}')
    turma.append(dados[:])
    perg = input('Deseja continuar[S/N]: ')
    if perg in 'Nn':
        break
for i,aluno in enumerate(turma):
    notas = (aluno[1] + aluno[2]) / 2
print(f'O aluno {aluno[0]} ficou com média {notas}')


import telebot
import requests

token = "1028814748:AAGxNeS3k3V4OvHNsw-xxXViXjxcqcju4vw"
bot = telebot.TeleBot(token)

@bot.message_handler(commands=["start"])
def say_hello(message):
    msg = 'Курс валют - /Valute\nПогода - /Weather'
    print(message)
    bot.send_message(message.chat.id, msg)

@bot.message_handler(commands=["Valute"])
def get_valute(message):
    url = 'https://www.cbr-xml-daily.ru/daily_json.js'
    currency = requests.get(url).json()
    #print(currency["Valute"])
    usd = currency["Valute"]["USD"]["Value"]
    eur = currency["Valute"]["EUR"]["Value"]
    bot.send_message(message.chat.id, f"Доллар: {usd}, Евро: {eur}")

@bot.message_handler(commands=["Weather"])
def get_city(message):
    msg = bot.send_message(message.chat.id,"Укажите, пожалуйста, ваш город ")
    bot.register_next_step_handler(msg, get_weather)

def get_weather(message):
    city = message.text
    url = f"http://api.openweathermap.org/data/2.5/weather?q={city}&appid=3c476f22a5b257b9d84b96dbf18ad854"
    data = requests.get(url).json()
    bot.send_message(message.chat.id, f"{city} - {(data['main']['temp'] - 273.15) //1} °Цельсия")

bot.polling()


# Third party imports
import os.path
import requests
import shutil
from flask import (Blueprint, after_this_request, current_app, flash, redirect, url_for)
from flask_security import (current_user, login_user)
# Ammcon imports
from ammcon_frontend.auth_providers import OAuthSignIn
from ammcon_frontend.models import User

blueprint = Blueprint('oauth', __name__)

@blueprint.route('/authorize/<provider>')
def oauth_authorize(provider):
    """ OAUTH authorization flow. """
    # Redirect user to main page if already logged in.
    if current_user.is_authenticated:
        current_app.logger.debug("Redirect authenticated user to main page.")
        return redirect(url_for('index'))
    else:
        # Otherwise redirect user to oauth authorisation url
        oauth = OAuthSignIn.get_provider(provider)
        return oauth.authorize()

@blueprint.route('/callback/<provider>')
def oauth_callback(provider):
    """ Sign in using OAUTH, and redirect back to main page. """
    # Redirect user to main page if already logged in.
    if current_user.is_authenticated:
        current_app.logger.debug("Redirect authenticated user to main page.")
        return redirect(url_for('index'))

    # Otherwise, attempt to sign user in using OAUTH
    oauth = OAuthSignIn.get_provider(provider)
    username, email, photo_url = oauth.callback()

    if email is None:
        # Note: Google returns email but other oauth services such as Twitter do not.
        current_app.logger.info('OAUTH login failed - null email received.')
        flash('Authentication failed.')
        return redirect(url_for('login'))
    elif not allowed_email(email):
        current_app.logger.info('Unauthorised email address attempted OAUTH login.')
        flash('You are not authorised to use AmmCon.', 'error')
        return redirect(url_for('login'))

    # Check whether the user (email address) already exists in the database.
    user = User.query.filter_by(email=email).first()
    # Create user if necessary.
    if not user:
        # Use first part of email if name is not available.
        if not username:
            username = email.split('@')[0]

        # Download profile picture from Google and save to disk (link expires after a while so need to save locally)
        filename = store_profile_picture(photo_url)

        # Create user object
        user = current_app.user_datastore.create_user(nickname=username, email=email, photo_url=filename)

        # default_role = user_datastore.find_role(name="end-user")

        # Give admin roles to preconfigured admin user if not already given
        if email == current_app.config['ADMIN_ACCOUNT']:
            current_app.user_datastore.add_role_to_user(user, 'admin')
        else:
            current_app.user_datastore.add_role_to_user(user, 'end-user')

        # Commit to database
        current_app.db.session.commit()
        current_app.logger.info('Created user for {0} with role {1}.'.format(user.email, user.roles))

    # Log in the user, and remember them for their next visit unless they log out.
    login_user(user, remember=True)

    @after_this_request
    # Need to call datastore.commit() after directly using login_user function to
    # make sure the Flask-Security trackable fields are saved to the datastore.
    # See: https://github.com/mattupstate/flask-security/pull/567
    def save_user(response):
        current_app.user_datastore.commit()
        current_app.logger.debug('Saved user {0} to database.'.format(user.email))
        return response

    return redirect(url_for('index'))

def allowed_email(email):
    """ Check if the email used to sign in is an allowed user of Ammcon. """
    if email in current_app.config['ALLOWED_EMAILS']:
        return True
    else:
        current_app.logger.info('Unauthorised user login attempt.')
    return False

def store_profile_picture(url):
    response = requests.get(url, stream=True)
    output_filename = url.replace(':', '').replace('/', '').replace('.', '') + '.jpg'

    current_app.logger.debug(os.path.join('static/', output_filename))

    with open(os.path.join(current_app.root_path, 'static/', output_filename), 'wb') as f:
        response.raw.decode_content = True
        shutil.copyfileobj(response.raw, f)
    return output_filename


from enum import Enum
from typing import List
from sqlalchemy import inspect
from sqlalchemy.ext.declarative import DeclarativeMeta

def model2dict(
    cls=None,
    include: List[str] = None,
    exclude: List[str] = None,
    unmapped: List[str] = None,
    include_none=False,
):
    """Adds todict() method to SQLAlchemy model class which returns attributes as dict

    :param include: Include given attributes only
    :param exclude: Exclude given attributes. Ignored if include is provided.
    :param unmapped: Unmapped attributes to add to the dict.
    :param include_none: Include attributes whose value is None
    :return: Returns dict of all mapped columns, relationships, composites and synonyms.
    """

    def _wrapper(cls):
        if isinstance(cls, DeclarativeMeta):

            def getval(obj):
                if hasattr(obj, "todict"):
                    return obj.todict()
                elif isinstance(obj, list):
                    return [getval(item) for item in obj]
                elif isinstance(obj, Enum):
                    return obj.name
                else:
                    return obj

            def _todict(self):
                inst_state = inspect(self)
                keys = [
                    c.key for c in inst_state.attrs if c.key not in inst_state.unloaded
                ]
                if include is not None:
                    keys = [key for key in keys if key in include]
                elif exclude is not None:
                    keys = [key for key in keys if key not in exclude]
                if unmapped is not None:
                    [keys.append(attr)
                     for attr in unmapped if hasattr(self, attr)]
                return {
                    key: getval(getattr(self, key))
                    for key in keys
                    if include_none is True or getattr(self, key) is not None
                }

            setattr(cls, "todict", _todict)
        return cls

    # decorator is used with parens
    if cls is None:
        return _wrapper

    # decorator is used without parens
    return _wrapper(cls)


from airflow import DAG
from airflow.operators.python_operator import PythonOperator
from airflow.contrib.hooks.snowflake_hook import SnowflakeHook
import logging
import airflow.utils
from datetime import timedelta

# create a logger
logger = logging.getLogger('airflow.task')

# Replace the following with values appropriate for your use
conn_id = 'snowflake_dev'

def get_conn():
    hook = SnowflakeHook(snowflake_conn_id=conn_id)
    return hook.get_conn()

def get_table_names(**kwargs):
    task_instance = kwargs['ti']
    with get_conn() as conn:
        c = conn.cursor()
        try:
            table_names = c.execute('SELECT TABLE_NAME FROM SNOWFLAKE_SAMPLE_DATA.INFORMATION_SCHEMA.TABLES').fetchall()
            task_instance.xcom_push(key='table_names', value=table_names)
        finally:
            c.close()

def log_col_name(**kwargs):
    task_instance = kwargs['ti']
    with get_conn() as conn:
        c = conn.cursor()
        try:

            col_name = c.execute(
                'SELECT COLUMN_NAME FROM SNOWFLAKE_SAMPLE_DATA.INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = %s LIMIT 1',
                task_instance.xcom_pull(task_ids='get_table_names', key='table_names')[0][0]
            ).fetchone()
            logger.info(f'Task executed successfully with result {col_name[0]}')
        finally:
            c.close()

# create a dictionary type variable that will hold the default args for the DAG
args = {
    "owner": "ocho",
    "start_date": airflow.utils.dates.days_ago(1),
    'depends_on_past': False,
    'retries': 0,
    'retry_delay': timedelta(minutes=2),
}

# create DAG
dag = DAG(
    dag_id='test_xcom',
    default_args=args
)

with dag:
    table_names = PythonOperator(
        task_id='get_table_names',
        python_callable=get_table_names,
        provide_context=True
    )

    log_col_name = PythonOperator(
        task_id='log_col_name',
        python_callable=log_col_name,
        provide_context=True
    )

    table_names >> log_col_name


import MeCab
import argparse
import os

parser = argparse.ArgumentParser()
parser.add_argument('-lf',  type=str, help='load file help')
parser.add_argument('-sd',  type=str, help='save file help')

opt = parser.parse_args()

DATA_NUM = sum([1 for _ in open(opt.lf)])
# データ数を設定
DEV_PAIR_NUM = 2000
TEST_PAIR_NUM = 2000
if DEV_PAIR_NUM + TEST_PAIR_NUM >= DATA_NUM:
    print("データ数が少ないです")
    exit()
TRAIN_PAIR_NUM = DATA_NUM-(DEV_PAIR_NUM+TEST_PAIR_NUM)
print("データ数:train ", TRAIN_PAIR_NUM, " ,dev ", DEV_PAIR_NUM , " ,test ", TEST_PAIR_NUM)

mecab = MeCab.Tagger ("-Owakati")
mecab.parse("")

source = []
target = []
with open(opt.lf) as f:
    for i, line in enumerate(f):
        line = line.strip()

        if "\t" in line:
            s = mecab.parse(line.rsplit("\t", 1)[0].replace("\t", " SEP "))
            t = mecab.parse(line.rsplit("\t", 1)[1])
            # 両方とも5単語以上のツイートリプライペアを使用
            if len(s) >= 5 and len(t) >= 5:
                source.append(s)
                target.append(t)
        # 設定したデータ数に達したら読み込みを終了
        if len(source) > DEV_PAIR_NUM + TEST_PAIR_NUM + TRAIN_PAIR_NUM:
            break

# 出力用のディレクトリを作成
os.makedirs(opt.sd, exist_ok=True)

# ファイル出力
with open(opt.sd + "/dev.src", "w") as f:
    for l in source[0:DEV_PAIR_NUM]:
        f.write(l)
with open(opt.sd + "/dev.tgt", "w") as f:
    for l in target[0:DEV_PAIR_NUM]:
        f.write(l)
with open(opt.sd + "/test.src", "w") as f:
    for l in source[DEV_PAIR_NUM:DEV_PAIR_NUM + TEST_PAIR_NUM]:
        f.write(l)
with open(opt.sd + "/test.tgt", "w") as f:
    for l in target[DEV_PAIR_NUM:DEV_PAIR_NUM + TEST_PAIR_NUM]:
        f.write(l)
with open(opt.sd + "/train.src", "w") as f:
    for l in source[DEV_PAIR_NUM + TEST_PAIR_NUM:DEV_PAIR_NUM + TEST_PAIR_NUM + TRAIN_PAIR_NUM]:
        f.write(l)
with open(opt.sd + "/train.tgt", "w") as f:
    for l in target[DEV_PAIR_NUM + TEST_PAIR_NUM:DEV_PAIR_NUM + TEST_PAIR_NUM + TRAIN_PAIR_NUM]:
        f.write(l)


from tsnecuda import TSNE
from matplotlib import pyplot as plt
import torch
from FakeNewsDataset import FakeNewsDataset
from FakeNewsModel import FakeNewsModel
import torch.utils.data as data
import torchvision.transforms as transform
from tqdm import tqdm
import time

device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')

batch_size = 64
transform = transform.Compose([transform.Resize((224, 224)), transform.ToTensor()])

test_dataset = FakeNewsDataset(train=False, transform=transform)
test_loader = data.DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=True, num_workers=8)

model = FakeNewsModel()
model.load_state_dict(torch.load("../data/model/resnet18x3_fft_ela_adaption_epoch30.pth"))
model = model.to(device)
feature_list = []
label_list = []

# Test
model.eval()
with torch.no_grad():
    for images, labels, fourier, ela in tqdm(test_loader):
        images = images.to(device)
        fourier = fourier.to(device)
        labels = labels.to(device)
        ela = ela.to(device)

        _, feature = model(images, fourier, ela)
        feature_list.append(feature)
        label_list.append(labels)

features = torch.Tensor.cpu(torch.cat(feature_list, 0))
X = TSNE(n_components=2).fit_transform(features)
labels = torch.Tensor.cpu(torch.cat(label_list, 0))

plt.figure()
for i in tqdm(range(len(X))):
    if labels[i].item() == 0:
        plt.plot(X[i, 0], X[i, 1], 'r.')
    else:
        plt.plot(X[i, 0], X[i, 1], 'g.')
plt.savefig("../data/visualize/{}.jpg".format(time.strftime("%y-%m-%d-%H-%M-%S", time.localtime())))


print("functions")
import statemachine
import config
import array, time
import random
import io
import math
import button
import init
import machine
import os
import micropython
import animation

micropython.alloc_emergency_exception_buf(100)

#decorator to measure the execution time of a function in ms
def measure_execution_time(func):
    def wrapper(*args, **kwargs):
        times = []
        iterations = 100
        for i in range(iterations):
            t1 = time.ticks_us()
            func(*args, **kwargs)
            t2 = time.ticks_us()-t1
            times.append(t2)
        average = sum(times) / len(times)
        #print(f'Took {t2/1000:.3f} ms')
        print(f'Took on average {average/1000:.3f} ms')
    return wrapper

#dummy interrupt, does nothing. Set a button handler to this if you want to do nothing on interrupt
def dummy(pin):
    pass

#timer interrupt function
#increases timer counter for every timer interrupt
def tick(timer):
    init.idle_counter += 1
    init.timer_counter += 1
    init.string_leniency += 1

#this function is called every 30 seconds
def save_stats(timer):
    if config.save_stats == False:
        return

    init.seconds_counter += 30

    lines = init.file_content
    updated_lines = []

    for line in lines:
        if line[0] == "#" or line == '\n':
            continue

        name, value = line.split(":")
        #name = name.strip()
        value = int(value)

        if name == 'uptime':
            value += init.seconds_counter
            init.idle_file_counter = 0
            init.seconds_counter = 0

        for button in config.button_list:
            if button.name == name:
                value += button.num_presses
                button.num_presses = 0

        updated_lines.append(f"{name}: {value}\n")

    content = init.header_text + ''.join(updated_lines)

    with open(init.file_name, "w") as f:
        f.write(content)

    content = [line + "\n" for line in content.split("\n")]
    init.file_content = content

#sets the idle_counter to the setback value which wakes the leds up from idle mode
def clear_led(pin):
    init.idle_counter = init.setback_value

#frequenzy in hz 0.016hz = 60sec, one timer interrupt every 60seconds
#freq=1 = 1hz = 1 interrupt every second
#freq=62.5 = 1 interrupt every 0.016 seconds (1 Frame in a 60FPS Fighting Game)
init.timer1.init(freq=init.frequency, mode=machine.Timer.PERIODIC, callback=tick)
init.timer3.init(freq=1/30, mode=machine.Timer.PERIODIC, callback=save_stats)

#interrupt routine to debounce the brightness button
#all credits to Kaspars Dambis @ https://kaspars.net/blog/micropython-button-debounce
def debounce_brightness(pin):
    # Start or replace a timer for 100ms, and trigger change_brightness.
    init.timer2.init(mode=machine.Timer.ONE_SHOT, period=100, callback=mode_select)#change_brightness)

#interrupt routine to debounce buttons, calls the clear_led method
#def debounce_clear_led(pin):
#    init.timer3.init(mode=machine.Timer.ONE_SHOT, period=50, callback=clear_led)

def increase_brightness():
    brightness = config.brightness_mod
    while config.brightness_mod < (brightness + config.brightness_steps):
        pixels_show(config.brightness_mod)
        config.brightness_mod += 0.005
        if config.brightness_mod >= 1:
            config.brightness_mod = 1
            return

def decrease_brightness():

    brightness = config.brightness_mod
    while config.brightness_mod > (brightness - config.brightness_steps):
        pixels_show(config.brightness_mod)
        config.brightness_mod -= 0.005
        if config.brightness_mod <= 0:
            config.brightness_mod = 0
            return

def pixels_show(brightness_input):
    dimmer_ar = array.array("I", [0 for _ in range(config.led_count)])
    brightness_scale = int(255 * brightness_input)
    for ii, cc in enumerate(statemachine.ar):
        r = (cc >> 8) & 0xFF
        g = (cc >> 16) & 0xFF
        b = cc & 0xFF
        r_scaled = (r * brightness_scale) >> 8
        g_scaled = (g * brightness_scale) >> 8
        b_scaled = (b * brightness_scale) >> 8
        dimmer_ar[ii] = (g_scaled << 16) | (r_scaled << 8) | b_scaled
    statemachine.sm.put(dimmer_ar, 8)

def pixels_set(i, color):
    statemachine.ar[i] = (color[1]<<16) + (color[0]<<8) + color[2] # set 24-bit color

def pixels_set_range(list, color):
    for i in list:
        pixels_set(i, color)

#sets a color at pos i, takes HSV color as value
def pixels_setHSV(i,color):
    rgbcolor = HSVtoRGB(color)
    pixels_set(i, rgbcolor)

#sets all leds to color in RGB
def pixels_fill(color):
    for i in range(len(statemachine.ar)):
        pixels_set(i, color)

#sets all leds to color in HSV
def pixels_fillHSV(colorHSV):
    colorRGB = HSVtoRGB(colorHSV)
    pixels_fill(colorRGB)

def print_stats():
    f = open(init.file_name, "r")
    lines = f.readlines()
    values = {}

    for line in lines:
        if line[0] == '#':
            continue

        var_name = ""
        value = ""
        for i in range(len(line)):
            if line[i] == ':':
                i += 2
                for j in range(i, len(line)):
                    value += line[j]
                break
            var_name += line[i]

        value = int(value[:-1])
        values[var_name] = value

    uptime = values['uptime']
    del values['uptime']

    print("-------------------------------")
    for key, value in sorted(values.items(), key=lambda item: item[1]):
        print("%s: %s" % (key, value))
    print('uptime:', seconds_to_time(uptime))

def seconds_to_time(seconds):
    minutes, seconds = divmod(seconds, 60)
    hours, minutes = divmod(minutes, 60)
    return "%dh:%dm:%ds" % (hours, minutes, seconds)

# Input a value 0 to 255 to get a color value.
# The colours are a transition r - g - b - back to r.
def wheel(pos):
    if pos < 0 or pos > 255:
        return (0, 0, 0)
    if pos < 85:
        return (255 - pos * 3, pos * 3, 0)
    if pos < 170:
        pos -= 85
        return (0, 255 - pos * 3, pos * 3)
    pos -= 170
    return (pos * 3, 0, 255 - pos * 3)

def alt_wheel(pos):
    if pos < 85:
        return (pos * 3, 255 - pos * 3, 0)
    elif pos < 170:
        pos -= 85
        return (255 - pos * 3, 0, pos * 3)
    else:
        pos -= 170
        return (0, pos * 3, 255 - pos * 3)

#returns the color in rgb of a LED
#not fully implemented yet
def get_pixelcolor(pos):
    r = int(((statemachine.ar[pos] >> 8) & 0xFF))
    g = int(((statemachine.ar[pos] >> 16) & 0xFF))
    b = int((statemachine.ar[pos] & 0xFF))
    return (r,g,b)

#shuffles an array
def shuffle_array(arr):
    last_index = len(arr)-1
    while last_index > 0:
        rand_index = random.randint(0,last_index)
        temp = arr[last_index]
        arr[last_index] = arr[rand_index]
        arr[rand_index] = temp
        last_index -= 1

#unused
def inverse_ledlist(ledlist):
    leds = []
    for i in range(config.led_count):
        leds.append(i)

    for i in range(len(ledlist)):
        leds.remove(ledlist[i])

    return leds

#converts the value of the idle_after variable in config.py to ticks of the timer interrupt
#example: if idle_after = 1 in config.py, then it would take 20 ticks for 1 second to pass, at a frequency of 20hz
def idle_after():
    if config.idle_after == 0:
        return 0
    else:
        ticks = 1/(1/init.frequency)
        return ticks * config.idle_after

def get_seconds(input):
    ticks = 1/(1/init.frequency)
    return ticks * input

#returns the id of a pin
def get_id(*args, **kwargs):
    output = io.StringIO()
    print(*args, file=output, **kwargs)
    s = output.getvalue()
    output.close()
    myid=s[s.find('(')+1:s.find(',')]
    return myid

#converts HSV to RGB, the RGB values go from 0-255
#the HSV Values go between:
#H between 0 and 359 (0° - 359°)
#S between 0 and 100 (0% - 100%)
#V between 0 and 100 (0% - 100%)
#might give error if Hs is undefined
#takes a HSV color as a tupel as argument (H,S,V)
#returns RGB as a tupel (R,G,B)
def HSVtoRGB(hsvcolor):
    H = hsvcolor[0]
    S = hsvcolor[1]
    V = hsvcolor[2]

    if H > 359:
        print("ERROR H can only take values from 0-359")
    if S > 100:
        print("ERROR S can only take values from 0-100")
    if V > 100:
        print("ERROR V can only take values from 0-100")

    S = S / 100
    V = V / 100

    C = V * S
    Hs = H / 60
    det = (Hs%2) - 1

    if det < 0:
        det = det * (-1)

    X = C * (1-det)
    if Hs >= 0 and Hs < 1:
        R = C
        G = X
        B = 0
    if Hs >= 1 and Hs < 2:
        R = X
        G = C
        B = 0
    if Hs >= 2 and Hs < 3:
        R = 0
        G = C
        B = X
    if Hs >= 3 and Hs < 4:
        R = 0
        G = X
        B = C
    if Hs >=4 and Hs < 5:
        R = X
        G = 0
        B = C
    if Hs >= 5 and Hs < 6:
        R = C
        G = 0
        B = X

    m = V-C

    R = (R+m)*255
    G = (G+m)*255
    B = (B+m)*255
    return (math.ceil(R), math.ceil(G), math.ceil(B))

#converts RGB Colors in range of 0-255 to HSV colors (0-359,0-100,0-100)
#takes an RGB tupel (R,G,B) as input, returns a HSV tupel (H,S,V)
def RGBtoHSV(rgbcolor):
    R = rgbcolor[0]/255
    G = rgbcolor[1]/255
    B = rgbcolor[2]/255
    Cmax = max(R,G)
    Cmax = max(Cmax, B)

    Cmin = min(R,G)
    Cmin = min(Cmin,B)

    delta = Cmax-Cmin

    if delta == 0:
        H = 0
    elif Cmax == R:
        modulus = ((G-B)/delta)
        H = 60*(modulus%6)
    elif Cmax == G:
        H = 60*(((B-R)/delta)+2)
    elif Cmax == B:
        H = 60*(((R-G)/delta)+4)

    if Cmax == 0:
        S = 0
    else:
        S = delta/Cmax

    V = Cmax

    H = math.ceil(H)
    S = math.ceil(S*100)
    V = math.ceil(V*100)

    if H > 359:
        H = 359
    if S > 100:
        S = 100
    if V > 100:
        V = 100

    return (H,S,V)

#helper function that helps with LED fade
#gets a value (usually the V of a HSV color)
#decreses the value defined by config.fed_speed and returns it
#if the value becomes negative it sets the value to 0
def fade_val_dec(color_val):
    if color_val >= 0:
        color_val -= config.fadeout_speed
        if color_val < 0:
            color_val = 0
    return color_val

def fade_val_inc(color_val):
    if color_val <= 100:
        color_val += config.fadein_speed
        if color_val > 100:
            color_val = 100
    return color_val

#helper function
#return true if no button is pressed at the moment
#returns false when a button is currently pressed
def no_buttons_pressed():
    for button in config.button_list:
        if button.is_pressed == True:
            return False

    return True

def set_background(background):
    #speed = 1000 #speed for colorwheel, higher = slower

    #if background it only a color
    if isinstance(background[0], int):
        if init.bg_initialized == False:
            init.bg_initialized = True

        pixels_fill(background)
        return
    elif background == 'rainbow':#if background is only 'rainbow'
        hsv_col = ((time.ticks_ms()/config.rainbow_speed)%359,100,100)
        pixels_fillHSV(hsv_col)
        return
    elif not isinstance(background[0], tuple) and init.bg_initialized == False:#if background is a single tuple
        init.ranges = list(background)
        init.brightness_values.append(init.ranges.pop(0))
        if init.brightness_values[0] > 1:
            init.brightness_values[0] = 1
        init.colors.append(init.ranges.pop(0))
        if not isinstance(init.colors[0], str):
            init.background_color = list(RGBtoHSV(init.colors[0]))
            init.background_color[2] *= init.brightness_values[0]
            init.background_color = HSVtoRGB(init.background_color)

        init.bg_initialized = True
        init.single_tuple = True

    elif init.bg_initialized == False:#if background is tuple of tuple
        #initialize the background colors
        different_tuple = len(background)

        #appends all the different tuple into ranges
        for tupel in background:
            init.ranges.append(list(tupel))

        for tupel in init.ranges:
            init.brightness_values.append(tupel.pop(0))

        #converts all the different colors into HSV and apppends them into the list init.colors
        for i in range(different_tuple):
            if isinstance(init.ranges[i][0], str):
                init.colors.append(init.ranges[i][0])
            else:
                hsv_col = list(RGBtoHSV(init.ranges[i][0]))
                hsv_col[2] *= init.brightness_values[i]
                hsv_col = HSVtoRGB(hsv_col)
                init.colors.append(hsv_col)

            init.ranges[i].pop(0)
        init.bg_initialized = True

    #display the background colors
    if init.single_tuple == True:
        for ranges in init.ranges:
            if init.colors[0] == 'rainbow':
                hsv_col = ((time.ticks_ms()/config.rainbow_speed)%359,100,100*init.brightness_values[0])
                pixels_setHSV(ranges-1,hsv_col)
            else:
                pixels_set(ranges-1, init.background_color)
    else:
        for i in range(len(init.ranges)):
            for j in range(len(init.ranges[i])):
                if init.colors[i] == 'rainbow':
                    hsv_col = ((time.ticks_ms()/config.rainbow_speed)%359,100,100*init.brightness_values[i])
                    pixels_setHSV(init.ranges[i][j]-1,hsv_col)
                else:
                    pixels_set(init.ranges[i][j]-1,init.colors[i])

def get_profile_color(config_name):
    file = open(config_name, 'r')
    color = 'blank'
    value = '(0,0,0)'
    #get the color name from 'profile_color' and save it in variable 'color'
    while True:
        line = file.readline()
        if 'profile_color' in line:
            line = line.replace('profile_color = ', '')
            line = line.strip()
            line = line.replace(' ', '')
            line = line.split('#',1)
            line = line[0]
            color = line
            file.close()
            break
        if not line:
            file.close()

    if color.startswith('('):
            color = color.replace('(','')
            color = color.replace(')','')
            color = eval(color)
            return color

    #get the value for 'color'
    file = open(config_name, 'r')
    color_def = color + ' = '
    while True:
        line = file.readline()
        if color_def in line:
            line = line.replace(color_def, '')
            line = line.strip()
            line = line.replace(' ', '')
            line = line.split('#',1)
            value = line[0]
            file.close()
            break
        if not line:
            file.close()
            break

    value = value.replace('(','')
    value = value.replace(')','')
    value = eval(value)
    return value

def list_to_string(list):
    my_string = ''

    for elements in list:
        my_string = my_string + elements + "+"

    return my_string[:-1]

def add_fgc_input(str, num):
    init.fgc_strings.append(str)
    copy = str[:]
    init.copy_strings.append(copy)
    init.animation_num.append(num)
    init.fgc_strings_length += 1

def play_animation(num):
        if num == 1:
            animation.fireball((7,8,6,9,5,10,4,11,3,12,2,13,1,14,0,15),config.orange) #example for led-chain with 15 leds
        if num == 2:
            animation.fireball((15,0,14,1,13,2,12,3,11,4,10,5,9,6,8,7),config.red) #example for led-chain with 15 leds
        if num == 3:
            animation.flash_all(config.red)
        return

def check_fgc_string():
    if init.fgc_strings_length == 0:
        return
    else:
        for i in range(init.fgc_strings_length):
            if init.fgc_strings[i][0] == init.current_input or not init.fgc_strings[i]:
                del init.fgc_strings[i][0]
            if not init.fgc_strings[i]:
                play_animation(init.animation_num[i])
                init.fgc_strings[i] = init.copy_strings[i].copy()

            if init.string_leniency > config.input_reset_time:
                init.string_leniency = 0
                for j in range(init.fgc_strings_length):
                    init.fgc_strings[j] = init.copy_strings[j].copy()

def mode_select():
    init.mode_selector = 0
    config_name = 'config.py'
    epsilon = 0.00001
    delay = 25

    #small animation at the beginning
    time.sleep_ms(delay)
    pixels_fill((0,0,0))
    pixels_show(config.brightness_mod)

    time.sleep_ms(delay)
    pixels_fill(((255,0,0)))
    pixels_show(config.brightness_mod)

    time.sleep_ms(delay)
    pixels_fill((0,0,0))
    pixels_show(config.brightness_mod)

    time.sleep_ms(delay)
    pixels_fill(((255,0,0)))
    pixels_show(config.brightness_mod)

    while True:
        pixels_fill(((255,0,0)))
        profile_color = get_profile_color(config_name)
        pixels_set(init.mode_selector, profile_color)
        if config.brightness_mod > 0:
            pixels_show(config.brightness_mod)
        if config.brightness_mod < epsilon:
            pixels_show(0.004)

        if config.ledOptions_increase_brightness:
            config.ledOptions_increase_brightness[0].run(0)

        if config.ledOptions_decrease_brightness:
            config.ledOptions_decrease_brightness[0].run(0)

        if config.ledOptions_confirm:
            config.ledOptions_confirm[0].run(0)

        if config.ledOptions_left_button:
            config.ledOptions_left_button[0].run(0)

        if config.ledOptions_right_button:
            config.ledOptions_right_button[0].run(0)

        if config.ledOptions_increase_brightness and config.ledOptions_increase_brightness[0].was_pressed:
            pixels_fill((255,0,0))
            pixels_set(init.mode_selector, profile_color)
            increase_brightness()
            print("brightness:", config.brightness_mod)
        if config.ledOptions_decrease_brightness and config.ledOptions_decrease_brightness[0].was_pressed:
            pixels_fill((255,0,0))
            pixels_set(init.mode_selector, profile_color)
            decrease_brightness()
            print("brightness:", config.brightness_mod)

        if config.ledOptions_right_button and config.ledOptions_right_button[0].was_pressed:
            init.mode_selector -= 1
            if init.mode_selector <= 0:
                init.mode_selector = 0
                config_name = "config.py"
            else:
                config_name = "config" + str(init.mode_selector) + ".py"

            try:
                f = open(config_name, "r")
                f.close()
            except OSError:
                init.mode_selector -= 1

        if config.ledOptions_left_button and config.ledOptions_left_button[0].was_pressed:
            init.mode_selector += 1
            config_name = "config" + str(init.mode_selector) + ".py"

            try:
                f = open(config_name, "r")
                f.close()

            except OSError:
                init.mode_selector -= 1
                config_name = "config" + str(init.mode_selector) + ".py"
                if init.mode_selector == 0:
                    config_name = "config.py"

        for button in config.ledOptions_led_buttons:
            button.run(0)

        #checks if all options button have been pressed at the same time
        all_pressed = True
        for button in config.ledOptions_led_buttons:
            if not button.was_pressed:
                all_pressed = False
                break

        if config.ledOptions_confirm[0].was_pressed or all_pressed: #confirm button
            if init.mode_selector == 0:
                config_name = 'config.py'
                pixels_fill((0,0,0))
                init.timer_counter = 0
                return
            else:
                path = os.rename(config_name, 'configtmp.py')
                path = os.rename('config.py', config_name)
                path = os.rename('configtmp.py', 'config.py')
                machine.reset()

#return interpolated (r,g,b) tuble between color1 and color2 depending on t (time)
#c1 and c2 = (r,g,b)
#t takes values between tstart and tend
def lerp_rgb(color1, color2, t):
    tstart = 0
    tend = 100
    red = color1[0] + (color2[0] - color1[0]) * ((t-tstart) / (tend - tstart))
    green = color1[1] + (color2[1] - color1[1]) * ((t-tstart) / (tend - tstart))
    blue = color1[2] + (color2[2] - color1[2]) * ((t-tstart) / (tend - tstart))

    return (int(red), int(green), int(blue))

def reset_background():
    init.bg_initialized = False
    init.single_tuple = False
    init.ranges = []
    init.colors = []
    init.brightness_values = []
    init.background_color_HSV = (0,0,0)
    init.background = 0

def lerp(tstart,tend,t):
    ystart = 0
    yend = 255
    y = ystart + (yend - ystart) * ((t-tstart)/(tend-tstart))
    return y


def fileExample():
    # Get input from user
    file_name = input("File name>")

    try:
        # Open file -> read binary
        f = open(file_name, "rb")

        # Create file -> write binary
        f2 = open("x_" + file_name, "wb")

        # Write contents to new file
        f2.write(f.read())

        # Close file
        f.close()
        f2.close()

    except FileNotFoundError as msg:
        print(str(msg))

if __name__ == "__main__":
    fileExample()


import os

# minimum settings.py
SECRET_KEY = 'katasandisayainisusah'
DEBUG = True
ROOT_URLCONF = 'urlsaya'

#Tambahan:
INSTALLED_APPS = [
    'app1'
]

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME' : os.path.join("", 'bootcamp.db')
    }
}

TEMPLATES = [
    {
        'DIRS': ['templates']
    }

]


import numpy as np
import random

s=0
arr=[]

for i in range(0,10):
    arr.append(random.randint(0,100))
    if (i)%2==0:
        s=s+arr[i]
print(arr)
print(s)


import numpy as np
from .base_decider import BaseConformalDecider
from scipy import stats

class TradeDecider(BaseConformalDecider):
    def __init__(self, horizon, eta, epsilon, target_returns, predicted_returns, dt, volatilities, loss_type="drawdown"):
        super().__init__(horizon=horizon, eta=eta, epsilon=epsilon)
        self.target_returns = target_returns
        self.predicted_returns = predicted_returns
        self.dt = dt
        self.volatilities = volatilities
        self.loss_type = loss_type
        assert self.loss_type in ("drawdown", "variance")

    @staticmethod
    def confidence_interval(prediction, alpha, vol, dt):
        z = stats.norm.ppf(1 - np.clip(alpha, 0, 1) / 2)
        return np.sort(prediction + vol * np.sqrt(dt) * z * np.array([-1, 1]))

    @staticmethod
    def get_action(interval):
        if interval[0] > 0:
            return 1
        elif interval[1] < 0:
            return -1
        else:
            return 0

    def loss_function(self, decision, target):
        """
        :param decision:
        :param target:
        :return:
        """
        action = decision["action"]
        if self.loss_type == "drawdown":
            return np.clip(-target * action, 0, None)
        elif self.loss_type == "variance":
            return np.abs(target * action)

    def decision_function(self, features, lam):
        """
        Use the confidence set build around the predicted return to decide whether to buy or sell.
        Buy if the confidence inverval is above 0
        Sell if the confidence interval is below 0
        """
        prediction = features["prediction"]
        vol = features["vol"]
        confidence_interval = self.confidence_interval(prediction=prediction, alpha=lam, vol=vol, dt=self.dt)
        return {"confidence_interval": confidence_interval,
                "action": self.get_action(interval=confidence_interval)}

    def update_target(self, t):
        return self.target_returns[t]

    def update_features(self, t, features, target):
        return {"prediction": self.predicted_returns[t],
                "vol": self.volatilities[t]}

    def update_others(self, t, features, target, decision, others, lam):
        if t == 0:
            others["coverage"] = np.full_like(self.target_returns, False)
            others["returns"] = np.zeros_like(self.target_returns)

        interval = decision["confidence_interval"]
        others["coverage"][t] = interval[0] <= target <= interval[1]
        others["returns"][t] = target * decision["action"]

        return others

class ACITradeDecider(TradeDecider):

    def __init__(self, horizon, eta, epsilon, target_returns, predicted_returns, dt, volatilities):
        super().__init__(horizon=horizon, eta=eta, epsilon=epsilon, target_returns=target_returns,
                         predicted_returns=predicted_returns, dt=dt, volatilities=volatilities)

    def loss_function(self, decision, target):
        interval = decision["confidence_interval"]
        cover = interval[0] <= target <= interval[1]
        return 1 - cover


import torch
import sys
import config
from config import get_ADE,get_FDE,get_1DE,get_2DE
from network.vector_net import VectorNet, VectorNetWithPredicting
from torch.utils.data import DataLoader, Dataset
from torch.utils.data import DataLoader
import numpy as np
import os
import math
from pathlib import Path
import torch.nn.functional as F
def distance_metric(traj_candidate: torch.Tensor, traj_gt: torch.Tensor):

    _, M, horizon_2_times,_ = traj_candidate.size()
    dis = torch.pow(traj_candidate - traj_gt.unsqueeze(1), 2).view(-1, M, int(horizon_2_times), 2)
    #print("ds: ",dis.shape)
    dis, _ = torch.max(torch.sum(dis, dim=3), dim=2)
    return dis

def calc_loss(output, label):
    traj_gt = outputs['traj_with_gt']
    trajs = outputs['trajs']
    score = outputs['score']
    mask_target_p_select = outputs['mask_target_p_select']
    target_select = outputs['target_select']
    offset = outputs['offset']
    #print("debug1: ",target.shape)
    loss = 0
   # print("loss: ",label.shape,trajs.shape,traj_gt.shape,mask_target_p_select.shape,target_select.shape)
   #print("loss1 shape: ", traj_gt.shape, trajs.shape)
    loss1 = F.mse_loss(traj_gt, label)
    score_gt = F.softmax(-distance_metric(trajs, traj_gt)/10.0, dim=1)
    #print("loss2 shape: ", score_gt[0,:])

    logprobs = - torch.log(score)
    loss2 = torch.sum(torch.mul(logprobs, score_gt))

    loss3 = F.binary_cross_entropy(
        target_select.float(), mask_target_p_select.float(), reduction='none').sum()
    t_offset =torch.zeros_like(offset)
    loss4 = F.mse_loss(t_offset, offset)
    print(loss1.item(),loss2.item(),loss3.item(),loss4.item())
    loss =loss1+loss2*0.01+loss3*0.01+loss4*10.0
    return loss

dataset0 = np.load("data_train_5000.npy",
                   allow_pickle=True)
print("load 1")
dataset_train = dataset0

batch = 64
torch.multiprocessing.set_sharing_strategy('file_system')
#train_loader = DataLoader(dataset, batch_size=batch, drop_last=True)
train_loader = DataLoader(
    dataset_train,
    batch_size=batch,
    shuffle=True,
    drop_last=True
)

# val_loader = DataLoader(
#     dataset_val,
#     batch_size=batch,
#     shuffle=False,
#     drop_last=True
# )
print("start train")

vector_net = VectorNetWithPredicting(12, time_stamp_number=30)
#vector_net = torch.load("/home/ljq/argoverse-api/ljq_test/net/3")
vector_net = vector_net.to(config.device)
learning_rate=0.001
decayed_factor=0.3
optimizer = torch.optim.Adam(vector_net.parameters(), lr=learning_rate)
loss_func = torch.nn.MSELoss()

loss_max=9999999999999
loss_max1=9999999999999
cnt = 0
vector_net.train()
for epoch in range(200):
    train_loss = 0
    val_loss=0

    cnt_train=1
    cnt_val=1
    for i, data in enumerate(train_loader):
        #print(i,data)
        cnt_train=i+1
        optimizer.zero_grad()
        labels = data["gt_preds"].to(torch.float32)
        # print(len(data["polyline_list1"]),
        #       data["item_num"].shape, data["idx"].shape)
        idd = torch.tensor([0]*batch)
        outputs = vector_net(data["item_num"].to(config.device), idd.to(
            config.device), data["polyline_list1"], data['near_centerline'].to(
            config.device), data['goal'].to(
            config.device),epoch)

        # loss = loss_func(outputs['traj_with_gt'], labels.to(config.device))
        loss = calc_loss(outputs,labels.to(config.device))

        loss.backward()
        optimizer.step()
        train_loss = train_loss+loss.item()

    if train_loss<loss_max:
        diff=math.fabs(train_loss-loss_max)/loss_max
        loss_max=train_loss
        if epoch %10==0:
            torch.save(vector_net, "/home/ljq/motion_prediction/save/"+str(epoch)+"  "+str(loss_max))
    #     print("sub ",diff)
    #     if  diff<0.05:
    #         print("sub1 ",diff)
    #         learning_rate *= decayed_factor
    #         optimizer = torch.optim.Adam(vector_net.parameters(), lr=learning_rate)
    if epoch != 0 and epoch % 20 == 0:
        learning_rate *= decayed_factor
        learning_rate =max(learning_rate,0.0003)
        optimizer = torch.optim.Adam(vector_net.parameters(), lr=learning_rate)
    cnt = cnt+1

    train_loss=train_loss/cnt_train/batch
    print("epoch  ",epoch," train loss: ",train_loss,learning_rate)


"""Utility injecting functionality, only use for debugging."""

import pdb
import sys

from buche import buche, reader

# Load custom hrepr methods for Graph etc.
from . import gprint  # noqa

def bucheg(graph, **kwargs):
    from myia.ir import ANFNode
    from myia.abstract import Inferrer
    def ttip(node):
        if isinstance(node, ANFNode):
            return node.abstract
    buche(graph, node_tooltip=ttip, function_in_node=True,
          graph_width='95vw', graph_height='95vh',
          **kwargs)

_log = []

def ibuche(*args, **kwargs):
    _log.append(args)
    buche(*args, interactive=True, **kwargs)

suite = {
    'buche': buche,
    'bucheg': bucheg,
    'ibuche': ibuche,
    'Subgraph': gprint.Subgraph,
}

def inject(**utilities):
    """Inject all utilities in the globals of every module."""
    for name, module in list(sys.modules.items()):
        glob = vars(module)
        for key, value in utilities.items():
            if key not in glob:
                try:
                    glob[key] = value
                except TypeError as e:
                    pass

def inject_suite():
    """Inject default utilities in the globals of every module."""
    inject(**suite)


from django.shortcuts import render
from django.views import View
from django.views.generic import TemplateView
from website.models import WebsiteSetting, Expertise, Clients, Testimonial, Article, ValuesItem, ServiceItem

# Create your views here.
class HomeView(TemplateView):
    template_name = 'index.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['websetting'] = WebsiteSetting.objects.last()
        context['expertise'] = Expertise.objects.all()
        context['clients'] = Clients.objects.all()
        context['testimonial'] = Testimonial.objects.all()
        context['articles'] = Article.objects.order_by('-timestamp')
        return context

class ContactView(TemplateView):
    template_name = 'contact.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['websetting'] = WebsiteSetting.objects.last()
        context['testimonial'] = Testimonial.objects.all()
        return context

class AboutView(TemplateView):
    template_name = 'about.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['websetting'] = WebsiteSetting.objects.last()
        context['valuesItem'] = ValuesItem.objects.all()
        context['testimonial'] = Testimonial.objects.all()
        return context

class ServiceView(TemplateView):
    template_name = 'services.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['websetting'] = WebsiteSetting.objects.last()
        context['testimonial'] = Testimonial.objects.all()
        context['servicesItem'] = ServiceItem.objects.all()
        return context

class BlogView(TemplateView):
    template_name = 'blog.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['websetting'] = WebsiteSetting.objects.last()
        context['articles'] = Article.objects.order_by('-timestamp')
        return context

class BlogDetailView(View):
    def get(self, request, article_id):
        article = Article.objects.get(id=article_id)
        context = {
            'article': article,
            'websetting': WebsiteSetting.objects.last()
        }
        return render(request, 'blog_details.html', context=context)


from __future__ import unicode_literals
class C(object):

    z = None
    i = 1

    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.z = 1

def f(x, y, z):

    c = C(x, y)
    c.a = z
    c.b = 2

    c.x
    c.y
    c.z
    c.a
    c.b

#Beware of cross talk, via some non-mapping global object (e.g. None)
def g(x, i, j):
    if x:
        d1 = None
    else:
        d1 = []
    d1[i] = 0.7
    d1[j]

def h(x, i, j):
    if x:
        d2 = None
    else:
        d2 = []
    d2[i] = 3
    d2[j]

#class attributes
def j():
    C.__init__
    C.i
    C.z

#Locally redefined attribute
def k(cond):
    c1 = C()
    c2 = C()
    c3 = C()
    c1.z = 10
    if cond:
        c2.z = 20
    c1.z # FP here due to self.attribute and local attribute
    c2.z
    c3.z
    c3.z = 30

class D(object):

    def meth1(self):
        self.a = 0
        self.b = 1
        self.a
        self.b

    def meth2(self):
        self.a = 7.0
        self.c = 2
        self.meth1()
        self.a
        self.b
        self.c

class E(object):

    def __init__(self, cond):
        if cond:
            self.x = 0
        else:
            self.x = 1

E().x

#Make sure that we handle getattr and setattr as well

class F(object):

    def meth1(self):
        setattr(self, "a",  0)
        setattr(self, "b",  1)
        getattr(self, "a")
        getattr(self, "b")

    def meth2(self):
        setattr(self, "a",  7.0)
        setattr(self, "c",  2)
        self.meth1()
        getattr(self, "a")
        getattr(self, "b")
        getattr(self, "c")

class G(object):

    def __init__(self):
        setattr(self, "x", 0)

G().x


# -*- coding: utf-8 -*-
#读取采样后每个mesh上的抓取数量，筛选出满足某些要求的mesh，并把这些合法mesh的路径保存在
# 某夹爪内部的legal_meshes_for_panda.txt中
# 远程测试
import  os
import sys
import pickle
import argparse
import numpy as np
import random

#解析命令行参数
parser = argparse.ArgumentParser(description='Check good meshes')
parser.add_argument('--gripper', type=str, default='baxter')
args = parser.parse_args()

#返回all_16k_stls文件夹下除了背景模型的其他所有stl路径
def get_stls_path(file_dir_):
    file_list = []
    for root, dirs, files in os.walk(file_dir_):
        for file in files:
            #剔除掉背景模型以及非stl文件
            if file.find('bg_')==-1 and file.find('.stl')!=-1:
                file_list.append(os.path.join(root,file))
    #排序
    #file_list.sort()
    return file_list

#返回
def get_grasp_files_path_name(file_dir_,method):
    file_list = []
    names = []
    for root, dirs, files in os.walk(file_dir_):
        for file in files:
            #
            if file.find(method)!=-1 and file.find('.npy')!=-1:
                file_list.append(os.path.join(root,file))
                names.append(file.split('_'+method)[0])
    #排序
    #file_list.sort()
    return file_list,names

if __name__ == '__main__':

    gripper_name = args.gripper
    #可以手动指定一些需要删除的mesh
    manual_delet_list = ['059_chain']

    print("Checking good meshes for {}.".format(gripper_name))

    home_dir = os.environ['HOME']
    meshes_16k_dir = home_dir+"/dataset/simulate_grasp_dataset/ycb/all_16k_meshes"
    #grasp 目录
    grasp_files_dir = home_dir+"/dataset/simulate_grasp_dataset/"+gripper_name+"/antipodal_grasps"
    #grasp files， name
    grasp_files_path,obj_names = get_grasp_files_path_name(grasp_files_dir,'pgpd')

    #获取{stl name:stl path}
    stls_path_list = get_stls_path(meshes_16k_dir)
    stl_name_path ={}
    for stl_path in stls_path_list:
        name = stl_path.split('/')[-1].split('.')[0]
        stl_name_path[name] = stl_path

    #获取{stl path: grasps}
    all_obj_grasps ={}
    #设定最小的分数阈值
    minimum_score = 2
    #首先是仅仅只将具有高分抓取的obj_name:grasps  保存起来
    for index,path in enumerate(grasp_files_path):
        grasp_with_score = np.load(path)   #(-1,10+1)
        #是希望物体有高分，不仅仅是抓取多
        if np.sum(grasp_with_score[:,-1]>minimum_score)>5:
            obj_name = obj_names[index]
            try:
                all_obj_grasps[stl_name_path[obj_name]]=grasp_with_score  #obj_name:grasps
            except:
                pass
            else:
                pass

    #剔除指定名称
    for index,del_name in enumerate(manual_delet_list):
        for stl_path,_ in all_obj_grasps.items():
            if stl_path.find(del_name)!=-1:
                break
        del all_obj_grasps[stl_path]

    #取出list
    final_paths=[]
    for stl_path,_ in all_obj_grasps.items():
        final_paths.append(stl_path)

    #随即从合法模型库中抽取一半放在里面
    #final_paths = final_paths+random.sample(final_paths,int(len(final_paths)/2))

    target = home_dir+"/dataset/simulate_grasp_dataset/"+gripper_name+"/good_meshes.pickle"
    #直接用pickel保存
    with open(target,'wb') as f:
        pickle.dump(final_paths, f)