## Aim
"""
Run this file
Main Graphical User Interface
"""

## Imports

from tkinter import *
from tkinter import filedialog
import cv2
import string
from PIL import Image, ImageTk
from text_detect_v4 import text_detect, bounding_boxes, spell_check
from movie_processor_v2 import movie_info, movie_poster, movie_recommend, display_info
import numpy as np
import threading
import pandas as pd
import time

## Objects

class Movie_Poster(object):
    def __init__(self, coord, poster_path=None, title=None, id=None):
        self.title = title
        self.x, self.y = coord
        self.poster_img = movie_poster(poster_path, id)
    def draw_poster(self, canvas):
        self.poster = ImageTk.PhotoImage(self.poster_img)
        canvas.create_image(self.x, self.y, anchor="c", image=self.poster)
    def resize(self, resize_height):
        self.resize_height = resize_height
        w, h = self.poster_img.size
        height = resize_height
        width = w/h * height
        self.poster_img = self.poster_img.resize((int(width),int(height)), Image.ANTIALIAS)
        return height/h #shrink factor
    def is_clicked(self, click_x, click_y):
        w, h = self.poster_img.size
        x0, y0, x1, y1 = self.x-w//2, self.y-h//2, self.x+w//2, self.y+h//2
        if x0 <= click_x <= x1 and y0 <= click_y <= y1:
            return True
        return False

#resize before getting bounding boxes
class Movie_Edit(Movie_Poster):
    def __init__(self, coord, poster_path = None):
        super().__init__(coord)
        if poster_path == None:
            poster = filedialog.askopenfilename()
        else:
            poster = poster_path
        self.boxes, poster = bounding_boxes(poster)
        self.orig_poster = poster
        poster = cv2.cvtColor(poster, cv2.COLOR_BGR2RGB)
        self.poster_img = Image.fromarray(poster)
        self.w, self.h = self.poster_img.size
        self.movie_name = None
        self.bounding_boxes = []
    def get_bounding_boxes(self):
        w, h = self.w, self.h
        for box in self.boxes:
            object_box = Bounding_Box(box)
            print(box, self.resize_height, h, object_box.get_coord(), "infoj")
            object_box.resize(w, h, self.resize_height, self.x, self.y)
            print(box, self.resize_height, h, object_box.get_coord(), "after")
            self.bounding_boxes.append(object_box)
    def check_spelling(self):
        self.movie_name = spell_check(self.movie_name)[0]
        return self.movie_name
    def find_text(self):
        box_coord = []
        for box in self.bounding_boxes:
            box.undo_resize()
            box_coord.append(box.get_coord())
        self.movie_name = text_detect(box_coord, self.orig_poster)
        print(self.movie_name)
        return self.movie_name
    def draw_poster(self, canvas):
        super().draw_poster(canvas)
        for box in self.bounding_boxes:
            box.draw_box(canvas)

class Bounding_Box(object):
    def __init__(self, coord):
        self.x0,self.y0,self.x1,self.y1 = coord
        self.x0_og,self.y0_og,self.x1_og,self.y1_og = coord
        self.clicked_side = None
        self.click_w = 5
    def draw_box(self, canvas):
        canvas.create_rectangle(self.x0, self.y0, self.x1, self.y1, width=3, outline="Green")
    def is_clicked(self, x, y):
        if abs(x-self.x0) <= self.click_w and self.y0 < y < self.y1:
            self.clicked_side = "left"
        elif abs(x-self.x1) <= self.click_w and self.y0 < y < self.y1:
            self.clicked_side = "right"
        elif abs(y-self.y0) <= self.click_w and self.x0 < x < self.x1:
            self.clicked_side = "top"
        elif abs(y-self.y1) <= self.click_w and self.x0 < x < self.x1:
            self.clicked_side = "bottom"
        else:
            self.clicked_side = None
    def shift_side(self, keysym):
        shift = 2
        if self.clicked_side == "left":
            if keysym == "Right":
                self.x0 += shift
            elif keysym == "Left":
                self.x0 -= shift
        elif self.clicked_side == "right":
            if keysym == "Right":
                self.x1 += shift
            elif keysym == "Left":
                self.x1 -= shift
        elif self.clicked_side == "top":
            if keysym == "Up":
                self.y0 -= shift
            elif keysym == "Down":
                self.y0 += shift
        elif self.clicked_side == "bottom":
            if keysym == "Up":
                self.y1 -= shift
            elif keysym == "Down":
                self.y1 += shift
    def get_coord(self):
        return (self.x0, self.y0, self.x1, self.y1)
    #resized height is after resizing image height, h is image original height
    def resize(self, w, h, resize_height, cx, cy):
        self.shrink_factor = resize_height/h
        resize_width = w * self.shrink_factor
        self.offset_x = cx - resize_width//2
        self.offset_y = cy - resize_height//2
        self.x0 = int(self.x0 * self.shrink_factor)
        self.y0 = int(self.y0 * self.shrink_factor)
        self.x1 = int(self.x1 * self.shrink_factor)
        self.y1 = int(self.y1 * self.shrink_factor)
        self.x0 += self.offset_x
        self.y0 += self.offset_y
        self.x1 += self.offset_x
        self.y1 += self.offset_y
    def undo_resize(self):
        self.x0 -= self.offset_x
        self.y0 -= self.offset_y
        self.x1 -= self.offset_x
        self.y1 -= self.offset_y
        self.x0 = int(self.x0/self.shrink_factor)
        self.y0 = int(self.y0/self.shrink_factor)
        self.x1 = int(self.x1/self.shrink_factor)
        self.y1 = int(self.y1/self.shrink_factor)

class Button(object):
    def __init__(self, name, coord, font_size, color="White"):
        self.name = name
        self.x0, self.y0, self.x1, self.y1 = coord
        self.font_size = font_size
        self.color = color
    def draw_button(self, canvas):
        canvas.create_text((self.x0+self.x1)//2, (self.y0+self.y1)//2,
                           text=self.name, font="Arial "+str(self.font_size)+" bold",
                           fill=self.color)
        canvas.create_line(self.x0, self.y1-5, self.x1, self.y1-5,fill="#E50914",
                           width=3)
    def is_clicked(self, click_x, click_y):
        if self.x0 <= click_x <= self.x1 and self.y0 <= click_y <= self.y1:
            return True
        return False

class Rating_Star(object):
    #Bool for full_star On Or Off
    def __init__(self, coord, size, full_star):
        self.x, self.y = coord
        self.size = size
        self.full_star = full_star
    def draw_star(self, canvas):
        if self.full_star:
            self.star = Image.open("user_data/star.png")
        else:
            self.star = Image.open("user_data/empty_star.png")
        self.star = self.star.resize((self.size, self.size), Image.ANTIALIAS)
        self.star = ImageTk.PhotoImage(self.star)
        canvas.create_image(self.x, self.y, anchor="c", image=self.star)
    def is_clicked(self, click_x, click_y):
        x0 = self.x - self.size//2
        y0 = self.y - self.size//2
        x1 = self.x + self.size//2
        y1 = self.y + self.size//2
        print(x0,y0,x1,y1, click_x, click_y)
        if x0 <= click_x <= x1 and y0 <= click_y <= y1:
            print("clicked")
            return True
        return False

## Variables

def size_to_canvas(data, button_coord):
    x0,y0,x1,y1 = button_coord
    width_scale = data.width/100
    height_scale = data.height/100
    x0 = x0 * width_scale
    y0 = y0 * height_scale
    x1 = x1 * width_scale
    y1 = y1 * height_scale
    return (x0,y0,x1,y1)

def init(data):
    data.mode = "login"
    data.cx, data.cy = data.width//2, data.height//2
    login_init(data)
    homescreen_init(data)
    camera_init(data)
    edit_init(data)
    movie_info_init(data)
    recommendations_init(data)

def login_init(data):
    login_button = Button("Login", size_to_canvas(data, (40,60,60,75)), 50, "Black")
    data.LOGIN_BUTTON = [login_button]
    data.username = ""
    data.app_name = Image.open("gui_files/name_small.png")
    data.app_name = data.app_name.resize((data.width//3, data.height//5))
    data.app_name = ImageTk.PhotoImage(data.app_name)
    data.current_user_id = None

def homescreen_init(data):
    photo_button = Button("Import Photo", size_to_canvas(data, (10,10,20,20)), 25)
    search_button = Button("Search", size_to_canvas(data, (80,10,90,20)), 25)
    camera_button = Button("Take Photo", size_to_canvas(data, (45,10,55,20)), 25)
    recommended_for_you_button = Button("Recommended For You",
                                        size_to_canvas(data, (35,80,65,95)), 30)
    data.HOMESCREEN_BUTTON = [photo_button, search_button,
                              recommended_for_you_button, camera_button]
    data.movie_title = ""

def camera_init(data):
    back_button = Button("Back", size_to_canvas(data, (5,5,15,15)), 25, "White")
    data.CAMERA_BUTTON = [back_button]

def edit_init(data):
    done_button = Button("Done", size_to_canvas(data, (10,10,20,20)), 25, "White")
    data.EDIT_BUTTON = [done_button]
    data.edit_poster = None
    data.bounding_boxes = None

def movie_info_init(data):
    home_button = Button("Home", size_to_canvas(data, (5,5,15,15)), 25)
    recommended_button = Button("Recommended Movies",
                                      size_to_canvas(data, (40,80,60,95)), 25)
    submit_button = Button("Submit", size_to_canvas(data, (90, 20, 95,25)), 15)
    data.MOVIE_INFO_BUTTON = [home_button, recommended_button, submit_button]
    def rating_system(data):
        data.display_star = Rating_Star((data.width-100,50), 60, True)
        data.rating_stars = []
        for i in range(5):
            sep = 30
            x = data.width - 150 + sep * i
            y = 100
            star = Rating_Star((x,y), 30, False)
            data.rating_stars.append(star)
        data.rating_open = False
    rating_system(data)

def recommendations_init(data):
    back_button = Button("Back", size_to_canvas(data, (5,5,15,15)), 20)
    data.RECOMMENDATIONS_BUTTON = [back_button]
    data.recommended_movies = []
    data.recommended_posters = []

## General

def mouse_pressed(event, data):
    if data.mode == "login": login_mouse_pressed(event, data)
    elif data.mode == "edit": edit_mouse_pressed(event, data)
    elif data.mode == "homescreen": homescreen_mouse_pressed(event, data)
    elif data.mode == "recommendations": recommendations_mouse_pressed(event, data)
    elif data.mode == "camera": camera_mouse_pressed(event, data)
    elif data.mode == "movie_info": movie_info_mouse_pressed(event, data)

def key_pressed(event, data):
    if data.mode == "login": login_key_pressed(event, data)
    elif data.mode == "edit": edit_key_pressed(event, data)
    elif data.mode == "homescreen": homescreen_key_pressed(event, data)
    elif data.mode == "recommendations": recommendations_key_pressed(event, data)
    elif data.mode == "camera": camera_key_pressed(event, data)
    elif data.mode == "movie_info": movie_info_key_pressed(event, data)

def redraw_all(canvas, data):
    if data.mode == "login": login_redraw_all(canvas, data)
    elif data.mode == "edit": edit_redraw_all(canvas, data)
    elif data.mode == "homescreen": homescreen_redraw_all(canvas, data)
    elif data.mode == "recommendations": recommendations_redraw_all(canvas, data)
    elif data.mode == "camera": camera_redraw_all(canvas, data)
    elif data.mode == "movie_info": movie_info_redraw_all(canvas, data)

def timer_fired(data):
    pass

## Login

def login_mouse_pressed(event, data):
    for button in data.LOGIN_BUTTON:
        if button.is_clicked(event.x, event.y):
            if button.name == "Login":
                if data.username != "":
                    initialize_login(data)
                    print("hello")
                    data.mode = "homescreen"

def initialize_login(data):
    users_data = pd.read_csv("user_data/user_data.csv")
    users = pd.read_csv("user_data/users.csv")
    if data.username not in users["username"].values:
        new_user_id = max(users_data["userId"]) + 1
        data.cur_user_id = new_user_id
        user = pd.DataFrame({"username": [data.username], "userId": [new_user_id]})
        users = users.append(user, ignore_index = True)
        user_data = dict()
        for col in users_data.columns:
            if col == "userId":
                user_data[col] = [new_user_id]
            else:
                user_data[col] = [0]
        user_data = pd.DataFrame(user_data)
        users_data = users_data.append(user_data, ignore_index = True)
        users_data.to_csv("user_data/user_data.csv", index = False)
        users.to_csv("user_data/users.csv", index = False)
    elif data.username in users["username"].values:
        data.cur_user_id = users[users["username"] == data.username].iloc[0, 1]
    data.users_data = users_data
    data.users = users

def login_redraw_all(canvas, data):
    #background
    canvas.create_rectangle(0, 0, data.width, data.height, fill="White")
    #logo
    canvas.create_image(data.width//2, data.height//5, anchor="c", image=data.app_name)
    #draws buttons
    for button in data.LOGIN_BUTTON:
        button.draw_button(canvas)
    #Input Line
    canvas.create_line(data.cx//2, data.cy, data.cx*3//2, data.cy, fill = "#E50914",
                       width=5)
    canvas.create_text(data.cx, data.cy-10, anchor = "s", text = data.username,
                       font="Arial 50 bold", fill="Black")

def login_key_pressed(event, data):
    print(event.keysym)
    if event.keysym == "BackSpace":
        if len(data.username) > 0:
            data.username = data.username[:-1]
    elif event.keysym in string.ascii_lowercase:
        data.username += event.keysym

## Homescreen

def homescreen_key_pressed(event, data):
    if event.keysym == "BackSpace":
        if len(data.movie_title) > 0:
            data.movie_title = data.movie_title[:-1]
    elif event.char in string.printable and event.keysym != "BackSpace":
        data.movie_title += event.char

def homescreen_redraw_all(canvas, data):
    canvas.create_rectangle(0,0,data.width,data.height,fill="Black")
    for button in data.HOMESCREEN_BUTTON:
        button.draw_button(canvas)
    #draw input box
    canvas.create_line(data.cx//2, data.cy, data.cx*3//2, data.cy, fill = "#E50914",
                       width=5)
    canvas.create_text(data.cx, data.cy-10, anchor="s", text=data.movie_title,
                       font="Arial 50 bold", fill="White")

def homescreen_mouse_pressed(event, data):
    for button in data.HOMESCREEN_BUTTON:
        if button.is_clicked(event.x, event.y):
            if button.name == "Import Photo":
                data.edit_poster = Movie_Edit((data.cx, data.cy))
                data.edit_poster.resize(data.height*4//5)
                data.edit_poster.get_bounding_boxes()
                data.mode = "edit"
            elif button.name == "Search":
                if movie_info(data.movie_title) != False:
                    execute_search(data)
                    data.mode = "movie_info"
            elif button.name == "Recommended For You":
                user_liked_genres = get_liked_genres(data)
                rec_movies_id = movie_recommend(user_liked_genres)
                display_num = len(rec_movies_id) if len(rec_movies_id) < 4 else 4
                for i in range(display_num):
                    movie_id = rec_movies_id[i]
                    _, rec_movie = movie_info(movie_id)
                    data.recommended_movies.append(rec_movie)
                    print(rec_movie["id"])
                    rec_poster = Movie_Poster((data.width*(i+1)//5 + 15*i - 30, data.cy), rec_movie["poster_path"], rec_movie["id"])
                    rec_poster.resize(data.height//2)
                    data.recommended_posters.append(rec_poster)
                data.mode = "recommendations"
            elif button.name == "Take Photo":
                data.mode = "camera"

def get_liked_genres(data):
    binarize_thresh = 0.5
    id = data.cur_user_id
    user_data_row = data.users_data[data.users_data["userId"] == id]
    thresh = binarize_thresh * max(user_data_row.iloc[0, 1:])
    genre_list = []
    for genre in user_data_row.columns[1:]:
        print(genre, user_data_row)
        if user_data_row.iloc[0][genre] >= thresh:
            genre_list.append(genre)
    print(genre_list)
    return genre_list

def execute_search(data):
    _, data.cur_movie_info = movie_info(data.movie_title)
    data.cur_poster = Movie_Poster((data.width//4, data.cy),
                                    data.cur_movie_info['poster_path'],
                                    data.cur_movie_info["original_title"],
                                    data.cur_movie_info["id"])
    data.cur_poster.resize(data.height*2//3)

## Camera

# Code from https://github.com/VasuAgrawal/112-opencv-tutorial/blob/master/opencvTkinterTemplate.py
def opencvToTk(frame):
    """Convert an opencv image to a tkinter image, to display in canvas."""
    rgb_image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    pil_img = Image.fromarray(rgb_image)
    tk_image = ImageTk.PhotoImage(image=pil_img)
    return tk_image

def camera_redraw_all(canvas, data):
    data.camera_frame = opencvToTk(data.frame)
    canvas.create_image(data.cx, data.cy, image=data.camera_frame)
    x, y, r = data.cx, data.height-100, 50
    canvas.create_oval(x-r, y-r, x+r, y+r, fill="Grey")
    for button in data.CAMERA_BUTTON:
        button.draw_button(canvas)

def camera_mouse_pressed(event, data):
    x, y, r = data.cx, data.height-100, 50
    for button in data.CAMERA_BUTTON:
        if button.is_clicked(event.x, event.y):
            if button.name == "Back":
                data.mode = "homescreen"
    if in_distance(x, y, r, event.x, event.y):
        cv2.imwrite("snap/snap_frame.jpg", data.frame)
        data.edit_poster = Movie_Edit((data.cx, data.cy), "snap/snap_frame.jpg")
        data.edit_poster.resize(data.height*4//5)
        data.edit_poster.get_bounding_boxes()
        data.mode = "edit"

def in_distance(x, y, r, click_x, click_y):
    if ((click_x - x)**2 + (click_y - y)**2)**(1/2) <= r:
        return True
    return False

def camera_key_pressed(event, data):
    pass

## Edit

def edit_key_pressed(event, data):
    for box in data.edit_poster.bounding_boxes:
        box.shift_side(event.keysym)

def edit_mouse_pressed(event, data):
    for button in data.EDIT_BUTTON:
        if button.is_clicked(event.x,event.y):
            if button.name == "Done":
                data.edit_poster.find_text()
                data.edit_poster.check_spelling()
                data.movie_title = data.edit_poster.movie_name
                data.mode = "homescreen"
    for box in data.edit_poster.bounding_boxes:
        box.is_clicked(event.x, event.y)

def edit_redraw_all(canvas, data):
    canvas.create_rectangle(0,0,data.width,data.height,fill="Black")
    data.edit_poster.draw_poster(canvas)
    for button in data.EDIT_BUTTON:
        button.draw_button(canvas)

## Movie Info

def movie_info_mouse_pressed(event, data):
    if data.display_star.is_clicked(event.x, event.y):
        data.rating_open = not data.rating_open
    for button in data.MOVIE_INFO_BUTTON:
        if button.is_clicked(event.x, event.y):
            if button.name == "Home":
                data.mode = "homescreen"
            elif button.name == "Recommended Movies":
                rec_movies_id = movie_recommend(data.cur_movie_info["genre_ids"],
                                                data.cur_movie_info["release_date"][:4])
                display_num = len(rec_movies_id) if len(rec_movies_id) < 4 else 4
                for i in range(display_num):
                    movie_id = rec_movies_id[i]
                    print(movie_id)
                    _, rec_movie = movie_info(movie_id)
                    data.recommended_movies.append(rec_movie)
                    rec_poster = Movie_Poster((data.width*(i+1)//5 + 15*i - 30, data.cy),
                                              rec_movie["poster_path"],
                                              rec_movie["original_title"],
                                              rec_movie["id"])
                    rec_poster.resize(data.height//2)
                    data.recommended_posters.append(rec_poster)
                data.mode = "recommendations"
            elif data.rating_open:
                if button.name == "Submit":
                    score = 0
                    for star in data.rating_stars:
                        if star.full_star == True:
                            score += 1
                    if score >= 3:
                        for genre in data.genres:
                            data.users_data.loc[data.users_data["userId"] == data.cur_user_id,
                                                [genre]] += 1
                        data.users_data.to_csv("user_data/user_data.csv", index = False)

                    data.rating_open = False
    for cur_star_index in range(len(data.rating_stars)):
        star = data.rating_stars[cur_star_index]
        if star.is_clicked(event.x, event.y):
            for i in range(len(data.rating_stars)):
                if i <= cur_star_index:
                    data.rating_stars[i].full_star = True
                else:
                    data.rating_stars[i].full_star = False

def movie_info_redraw_all(canvas, data):
    #background
    canvas.create_rectangle(0,0,data.width,data.height,fill="Black")
    #draw poster:
    data.cur_poster.draw_poster(canvas)
    #draw buttons
    for button in data.MOVIE_INFO_BUTTON:
        if button.name != "Submit":
            button.draw_button(canvas)
        elif data.rating_open:
            button.draw_button(canvas)
    #draw info
    score, data.genres, lines = draw_info(canvas, data)
    #draw rating system
    draw_rating_system(canvas, data, score)
    draw_genre_system(canvas, data, data.genres, lines)

def draw_genre_system(canvas, data, genres, lines):
    for i in range(len(genres)):
        genre = genres[i]
        x0 = data.width*3//7+90*i+10
        y0 = data.height-330+lines*19
        x1 = data.width*3//7+90*(i+1)
        y1 = data.height-300+lines*19
        canvas.create_rectangle(x0,y0,x1,y1,outline="#E50914",width=3)
        canvas.create_text((x1-x0)//2+x0, (y1-y0)//2+y0, text=genre, fill="#E50914")

def draw_rating_system(canvas, data, score):
    data.display_star.draw_star(canvas)
    canvas.create_text(data.width-60, 50, anchor = "w", text=str(score),
                       font="Arial 30 bold", fill="Grey")
    if data.rating_open:
        for star in data.rating_stars:
            star.draw_star(canvas)

def draw_info(canvas, data):
    score, title, lang, release_date, overview, genres = display_info(data.cur_movie_info)
    info_text = "Language: " + lang + "\nRelease Date: " + release_date + "\nOverview: \n" + overview
    canvas.create_text(data.width*3//7, data.height//4, anchor = "nw", text = info_text,
                       fill="White", font="Arial 20")
    canvas.create_text(data.width*3//7, data.height//6, anchor = "nw", text = title,
                       fill="White", font="Arial 40 bold")
    return score, genres, len(overview.split("\n"))

## Recommendation

def recommendations_mouse_pressed(event, data):
    for movie in data.recommended_posters:
        if movie.is_clicked(event.x, event.y):
            data.movie_title = movie.title
            if movie_info(data.movie_title) != False:
                execute_search(data)
                data.mode = "movie_info"

    for button in data.RECOMMENDATIONS_BUTTON:
        if button.is_clicked(event.x, event.y):
            if button.name == "Back":
                if data.movie_title != "":
                    data.mode = "movie_info"
                else:
                    data.mode = "homescreen"
def recommendations_redraw_all(canvas, data):
    canvas.create_rectangle(0,0,data.width,data.height,fill="Black")
    for poster in data.recommended_posters:
        poster.draw_poster(canvas)
    for button in data.RECOMMENDATIONS_BUTTON:
        button.draw_button(canvas)

## Run Function

# Taken from the 15-112 webpage
# Integrated with code from https://github.com/VasuAgrawal/112-opencv-tutorial/blob/master/opencvTkinterTemplate.py
def run(width=1000, height=600):
    # def redraw_all_wrapper(canvas, data):
    #     canvas.delete(ALL)
    #     canvas.create_rectangle(0, 0, data.width, data.height,
    #                             fill='white', width=0)
    #     redraw_all(canvas, data)
    #     canvas.update()

    def mouse_pressed_wrapper(event, canvas, data):
        mouse_pressed(event, data)
        redraw_all_wrapper(canvas, data)

    def key_pressed_wrapper(event, canvas, data):
        key_pressed(event, data)
        redraw_all_wrapper(canvas, data)

    # Set up data and call init
    class Struct(object): pass
    data = Struct()
    data.width = width
    data.height = height
    data.camera_index = 0
    data.timer_delay = 100 # milliseconds
    data.redraw_delay = 50 # ms
    camera = cv2.VideoCapture(data.camera_index)
    #https://www.codingforentrepreneurs.com/blog/open-cv-python-change-video-resolution-or-scale/
    def make_1080p():
        camera.set(3, 1920)
        camera.set(4, 1080)
    make_1080p()
    data.camera = camera
    data.root = Tk()
    #creates Entry widget
    data.root.resizable(width=False, height=False) # prevents resizing window
    init(data)
    # create the root and the canvas
    canvas = Canvas(data.root, width=data.width, height=data.height)
    canvas.configure(bd=0, highlightthickness=0)
    canvas.pack()
    # set up events
    data.root.bind("<Button-1>", lambda event:
                            mouse_pressed_wrapper(event, canvas, data))
    data.root.bind("<Key>", lambda event:
                            key_pressed_wrapper(event, canvas, data))

    def timer_fired_wrapper(canvas, data):
        start = time.time()
        timer_fired(data)
        redraw_all_wrapper(canvas, data)
        end = time.time()
        diff_ms = (end - start) * 1000
        delay = int(max(data.timer_delay - diff_ms, 0))
        # pause, then call timerFired again
        canvas.after(delay, timer_fired_wrapper(canvas, data))
    data.root.after(data.timer_delay, lambda: timer_fired_wrapper(canvas,data))
    def redraw_all_wrapper(canvas, data):
        start = time.time()
        if data.mode == "camera":
            _, data.frame = data.camera.read()
            #camera_fired(data)
        canvas.delete(ALL)
        canvas.create_rectangle(0, 0, data.width, data.height,
                                fill='white', width=0)
        redraw_all(canvas, data)
        end = time.time()
        diff_ms = (end - start) * 1000
        delay = int(max(data.redraw_delay - diff_ms, 5))
        #data.root.after(delay, lambda: redraw_all_wrappuer(canvas, data))
        canvas.update()

    # and launch the app
    data.root.mainloop()  # blocks until window is closed
    data.camera.release()
    print("bye!")

run(1000, 600)


""" Log Module for retrieve the logs of the pod."""

__author__ = "Mariano Jose Abdala"
__version__ = "0.1.0"

from kubernetes.client.exceptions import ApiException
from devopscenter.modules.kube.namespace.commands.base_cmd import BaseCmd
from devopscenter.modules.kube.cluster_utils import get_container_name

class LogsCmd(BaseCmd):
    """Manage how the logs are printed."""

    def __exec_and_show_logs(self, pod_name, container_name):
        """ Exectute the command and print the logs."""
        try:
            logs = self.core.read_namespaced_pod_log(
                namespace=self.namespace,
                name=pod_name,
                container=container_name,
                _preload_content=False,
            )

            for line in logs.stream():
                self.print(line.decode("UTF-8"))
        except ApiException as api_ex:
            self.log(api_ex)
        except KeyboardInterrupt:
            self.log("Breaking logs")
            return
        except Exception as ex:  # pylint: disable=broad-except
            self.log(ex)

    def execute(self, args):
        """
        Does the real execution of the command.

        :param args arguments taken from the interface
        :param pods list of pods to be used
        """
        if len(args) < 2:
            self.log(
                "[red]Error you should select the number of the pod to show the log. Eg logs 0.0[/red]"
            )
            return

        try:
            pod_index, container_index = args[1].split(".")
        except ValueError:
            self.log(
                "[red]Error you should select the number of the pod to show the log. Eg logs 0.0[/red]"
            )
            return
        pods = self.get_pods(self.core, self.namespace)
        pod = self.get_pod(int(pod_index), pods)
        container_name = get_container_name(pod, int(container_index))
        self.__exec_and_show_logs(pod.pod_name, container_name)


from datetime import datetime, time
import xlrd, math
import logging
import tempfile
import binascii
from odoo import models, fields, _, api
from odoo.exceptions import ValidationError
_logger = logging.getLogger(__name__)

try:
	import csv
except ImportError:
	_logger.debug('Cannot `import csv`.')
try:
	import xlwt
except ImportError:
	_logger.debug('Cannot `import xlwt`.')
try:
	import cStringIO
except ImportError:
	_logger.debug('Cannot `import cStringIO`.')

try:
	import base64
except ImportError:
	_logger.debug('Cannot `import base64`.')

DEFAULT_SERVER_DATE_FORMAT = "%Y-%m-%d"
DEFAULT_SERVER_TIME_FORMAT = "%H:%M:%S"
DEFAULT_SERVER_DATETIME_FORMAT = "%s %s" % (DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_TIME_FORMAT)
from pytz import timezone, UTC
tz = 'Asia/Riyadh'

class ImportHrAttendanceWizard(models.TransientModel):
    _name = 'jood.import'

    file = fields.Binary('File')
    filename = fields.Char('Filename')
    branch_id = fields.Many2one('company.branches', 'Branch', required=True)

    def import_file(self):
        if not self.file:
            raise ValidationError(_("Please Upload File to Import Donations !"))

        try:
            file = tempfile.NamedTemporaryFile(delete=False, suffix=".xlsx")
            file.write(binascii.a2b_base64(self.file))
            file.seek(0)
            workbook = xlrd.open_workbook(file.name)
            sheet = workbook.sheet_by_index(0)
        except Exception:
            raise ValidationError(_("Please Select Valid File Format !"))

        list = []
        for row_no in range(1, sheet.nrows):
            dt = datetime(*xlrd.xldate.xldate_as_tuple(sheet.cell(row_no, 11).value, workbook.datemode))
            year, month, day, hour, minute, second = xlrd.xldate_as_tuple(sheet.cell(row_no, 11).value, workbook.datemode)

            vals = {
                'number': sheet.cell(row_no, 0).value,
                'partner': sheet.cell(row_no, 1).value,
                'mobile': str(int(sheet.cell(row_no, 2).value)),
                'project_title': sheet.cell(row_no, 3).value,
                'title': sheet.cell(row_no, 4).value,
                'categ': sheet.cell(row_no, 5).value,
                'type': sheet.cell(row_no, 6).value,
                'amount': sheet.cell(row_no, 8).value,
                'payment_method': sheet.cell(row_no, 9).value,
                'bank_acc': sheet.cell(row_no, 10).value,
                'date': timezone(tz).localize(
                        datetime.combine(dt, time(int(hour), int(minute), int(second)))).astimezone(UTC).replace(tzinfo=None),
                'state': sheet.cell(row_no, 12).value,
            }
            list.append(vals)
        self.create_donations(list)

    def create_donations(self, list):
        Donation = self.env['donation.donation']
        for line in list:
            partner = self.env['res.partner'].search([('name', 'like', line['partner']), ('mobile', '=', str(int(line['mobile'])))])
            if not partner:
                partner = self.env['res.partner'].create({
                    'name': line['partner'] if line['partner'] else line['mobile'],
                    'mobile': str(int(line['mobile'])),
                    'is_donor': True
                })
            payment_method_type = 'cash'
            if line['payment_method'] == 'بطاقة ائتمانية':
                payment_method_type = 'card'
            instruction = ''
            if len(line['project_title'].split(' / ')) == 1:
                product = self.env['product.product'].search([('name', 'like', line['project_title'])], limit=1)
            else:
                product = self.env['product.product'].search([('name', 'like', line['project_title'].split(' / ')[0])], limit=1)
                instruction = line['project_title'].split(' / ')[1]

            if not product:
                product = self.env['product.product'].search([('name', 'like', 'الصدقه النقديه العامه')], limit=1)
            Donation.create({
            # print({
                'payment_reference': line['number'],
                'donation_date': line['date'],
                'partner_id': partner.id,
                # 'branch_id': self.branch_id.id,
                'donation_type': 'money',
                'payment_method_type': payment_method_type,
                'donation_line':[(0, 0, {
                    'product_id': product.id,
                    'product_qty': 1,
                    'unit_price': line['amount'],
                    'instruction': instruction
                })]
            })


import random
import time

t_start = time.perf_counter()

def PolyHash(P, l, p, x):
    res = 0
    for i in reversed(range(l)):
        res = (res * x + ord(P[i])) % p
    return res % p

def PrecomputeHashes(T, l, k, p, x):
    H = [0] * (l - k + 1)
    S = T[l - k: l]
    H[l - k] = PolyHash(S, k, p, x)
    y = 1
    for i in range(1, k + 1):
        y = (y * x) % p
    for i in range(l - k - 1, -1, -1):
        H[i] = (x * H[i + 1] + ord(T[i]) - y * ord(T[i + k]) + p) % p
    return H

print('Время работы: %s секунд' % (time.perf_counter() - t_start))
with open('input.txt', 'r') as f:
    while True:
        text = f.readline()
        if not text:
            exit()
        w1, w2 = map(str, text.split())
        len_w1, len_w2 = len(w1), len(w2)
        k = min(len_w1, len_w2)
        p = 10 ** 9 + 7
        x = random.randint(1, p - 1)
        ok = False
        for i in reversed(range(1, k + 1)):
            hash_w1 = PrecomputeHashes(w1, len_w1, i, p, x)
            hash_w2 = PrecomputeHashes(w2, len_w2, i, p, x)
            for j in range(len(hash_w1)):
                for h in range(len(hash_w2)):
                    if hash_w1[j] == hash_w2[h]:
                        print(j, h, i)
                        ok = True
                        break
                if ok:
                    break
            if ok:
                break
        if not ok:
            print(0, 1, 0)


def obter_param_dois():
  a = []; t = []
  a.append(1.0); a.append(1.0)
  t.append(-0.577350269)
  t.append(0.577350269)
  return a, t

def obter_param_tres():
  a = []; t = []
  a.append(0.555555555); a.append(0.555555555)
  a.append(0.888888889)

  t.append(-0.774596667); t.append(0.774596667)
  t.append(0.0)
  return a, t

def obter_param_quatro():
  a = []; t = []
  a.append(0.34785484); a.append(0.65214516)
  a.append(0.65214516); a.append(0.34785484)

  t.append(-0.86113631); t.append(-0.33998104)
  t.append(0.33998104); t.append(0.86113631)
  return a, t

def obter_mapa_parametros():
  parametros = dict()
  parametros[2] = obter_param_dois
  parametros[3] = obter_param_tres
  parametros[4] = obter_param_quatro
  return parametros

def obter_parametros(m = 4):
  parametros = obter_mapa_parametros()
  a, t = parametros[m]()
  return a, t

def obter_m_maximo():
  return len(obter_mapa_parametros()) + 1


# Import your libraries
import pandas as pd
import numpy as np
# Start writing code
max_users =  len(list(set(list(facebook_friends.user2.unique() ) + list(facebook_friends.user1.unique()))))

revert = facebook_friends.rename(columns = {'user1' : 'user2', 'user2':'user1'})
Grouped = pd.concat([revert, facebook_friends]).drop_duplicates()
result = Grouped.groupby('user2').count().sort_values(by = ['user1'],ascending=False)
result = result/ max_users *100


import pandas as pd
from data import sdb_connect

def get_salt_astronomers():
    from schema.user import User
    conn = sdb_connect()
    sql = """
            select * from SaltAstronomers
                join Investigator using (Investigator_Id)
                join PiptUser using (Investigator_Id)
            where FirstName != "Techops"
        """
    astronomers = [User(
        first_name=row["FirstName"],
        last_name=row["Surname"],
        email=row["Email"],
        username=row["Username"]
    ) for i, row in pd.read_sql(sql, conn).iterrows()]

    conn.close()

    return astronomers


import re

class WordlePlayer:
    """A generic boilerplate implementation of a Wordle Player.

    Contains all the basic functionality to solve a game of Wordle (defined in
    the WordleGame class) semi-competently.

    Attributes:
        wordList: Set on initialization, this is a list of words meant to
          represent the list of words that the player can use as guesses.
          Naturally, this means that this list should at least contain all
          possible answers, but can include more. No implementation should alter
          this list directly, as the base class assumes it's always complete. It
          is assumed that the length of every word in the list is a uniform
          length.
        alphabet: A hard-coded list of all letters in lower case. This should
          also never be tampered with as it's used in reset() to establish the
          knowledge dictionary.
        pSpace: The working list of possible options. This list is reset with
          the reset() method to be a copy of wordList.
        playedWords: An internal record of the words that the Player has played
          in previous rounds, in the order they were played.
        feedback: An internal record of the feedback for each word the Player
          has played in previous rounds.
        knowledge: The representation of our knowledge about each letter. The
          keys are the letters in the alphabet, and they map to a nested list
          we'll call L. L[0] is a list of all indices of the solution word that
          we know are our letter (it defaults to an empty list). L[1] is a list
          of all the indices of the solution word that we know for certain are
          not the letter, prepended by a boolean flag at L[1][0]. If L[1][0] is
          True, that means that we know the letter is not in the word at all (it
          defaults to False).
    """

    def __init__(self, wordList):
        """Initializes a WordlePlayer's default state.

        Sets its wordList with the passed argument. The wordList can and should
        be referenced to help solve the puzzle, but it should *not* be altered
        in any way.

        Creates the alphabet attribute.

        Also initializes the other documented attributes of the Player by making
        a call to the reset() method.

        Args:
            wordList: The list of all words that the Player could guess. While
            the game of Wordle uses only 5-letter words, the player will accept
            wordLists with words of any length, so long as every word in the
            list is of uniform length.
        """
        self.wordList = wordList
        self.alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
                         'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
                         'w', 'x', 'y', 'z']
        self._reset()

    def reset(self):
        """Resets the state of the WordlePlayer so they can begin a new game.

        The following attributes are set to their default states: pSpace
        (defaults to a copy of wordList), playedWords, feedback, and knowledge.
        """
        self.pSpace = self.wordList.copy()
        self.playedWords = []
        self.feedback = []
        self.knowledge = {x: [[], [False]] for x in self.alphabet}
    _reset = reset

    def playWord(self):
        """The method that returns the word to be played this round.

        The default implementation of this method is to transfer the word in
        index 0 of the possibility space (self.pSpace) to the list of played
        words (self.playedWords), removing it from there and finally returning
        it. No decision making is intended to be made in this method.
        """
        self.playedWords.append(self.pSpace.pop(0))
        return self.playedWords[-1]

    def takeFeedback(self, response):
        """Uses the feedback passed in and its own memory to narrow its choices.

        This is where the magic happens. This method is intended to cross-
        reference the list of playedWords with the feedback string passed in to
        expand its knowledge base and prune its possibility space. It's the
        design intent that even if nothing else in a subclass is overridden, a
        change to this will change the strategy of how it plays.

        Args:
            response: The feedback string that corresponds to the last word
              played by this Player.
        """
        # First we update our knowledge dictionary with the new informaiton we
        # just got.
        self.feedback.append(response)
        lastWord = self.playedWords[-1]
        for i in range(len(lastWord)):
            # Update our knowledge-base dictionary
            letter = lastWord[i]
            knowns = self.knowledge[letter][0]
            excls = self.knowledge[letter][1]

            # Check if there's more than one of a letter in the word.
            doubleCheck = lastWord.replace(letter, "")
            doubles = len(lastWord) - len(doubleCheck) > 1

            if response[i] == "G":
                # We've just heard a new letter's position definitively
                if i not in knowns:
                    knowns.append(i)
            elif response[i] == "Y":
                # We've heard the letter is in the word, but not where we placed
                # it.
                if i not in excls:
                    excls.append(i)
            else:
                # The only other character in response strings are underscores.
                # If we get an underscore that usually means that the letter is
                # not in the word at all, but there's an edge case when the
                # letter appears more than once.
                if not excls[0] and not doubles:
                    # If we haven't already universally excluded it, and there's
                    # no chance that this is the edge case brought on by double
                    # letters, then we know to universally exclude it.
                    excls[0] = True
                elif doubles:
                    # If this is a double letter, we need to check if it's in
                    # the word elsewhere before we definitively say it's not.
                    notInWord = True
                    for j in range(len(lastWord)):
                        if lastWord[j] == letter and j != i:
                            notInWord = notInWord and response[j] == response[i]
                    excls[0] = notInWord

        # Now we prune our possibility space. Start by composing as much of the
        # word as we know:
        knownSoFar = ["." for i in range(len(self.wordList[0]))]
        for letter in self.knowledge:
            for index in self.knowledge[letter][0]:
                knownSoFar[index] = letter
        compositeSoln = "".join(knownSoFar)

        # Build a new pSpace from pSpace
        todo = self.pSpace.copy()
        keepList = []
        while todo:
            word = todo.pop(0)

            # First check if the word could be a match for our known letters.
            keep = re.fullmatch(compositeSoln, word) is not None

            # Then, assuming it was, check letter by letter against the
            # exclusions list
            i = 0
            while keep and i < len(word):
                letter = word[i]
                excls = self.knowledge[letter][1]
                # Reminder: excls[0] is "Not in the word" and any remaining
                # elements in the excls are indices we know the letter is not in
                keep = keep and not excls[0] and i not in excls[1:]
                i += 1
            if keep:
                keepList.append(word)
        self.pSpace = keepList

        # This is where we'd sort pSpace by some function determining which of
        # the remaining words should be our next guess.


from app.models.functions.get_path import get_path

import os
import logging

def get_logger(path : str) -> logging.Logger:

    logger = logging.getLogger('logger')
    log_file_path = get_path(os.path.join(path, 'LOG.log'))

    logging.basicConfig(
        filename    = log_file_path,
        level       = logging.DEBUG,
        encoding    = 'utf-8',
        format      = '%(asctime)s %(levelname)s %(module)s - %(funcName)s: %(message)s',
        datefmt     = '%Y-%m-%d %H:%M:%S',
    )

    log_formatter = logging.Formatter(
        fmt='%(asctime)s %(levelname)s %(module)s - %(funcName)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S')

    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.WARNING)
    console_handler.setFormatter(log_formatter)

    logger.addHandler(console_handler)
    logger.info('Logger instanciado.')


__author__ = 'Jose Maria Zambrana Arze'
__email__ = 'contact@josezambrana.com'
__version__ = '0.1'
__copyright__ = 'Copyright 2012, Mandla Web Studio'

from time import time

from django.db import models
from django.contrib.auth.models import User
from django.template.defaultfilters import slugify
from django.utils.translation import ugettext_lazy as _

class Content(models.Model):
    """
    Modelo base con atributos primarios para los contenidos que son visibles
    en el sitio.
    """

    #: Nombre del contenido
    name = models.CharField(_('Nombre'), max_length=255)
    #: Slug para usarse en la url y mostrar el contenido
    slug = models.SlugField(_('slug'))

    #: El usuario propietario del contenido
    user = models.ForeignKey(User, verbose_name=_(u'Propietario'))

    #: Fecha de creación del contenido
    created_at = models.DateTimeField(_(u'Fecha de creación'),
            auto_now_add=True)

    #: Fecha de última actualización del contenido
    updated_at = models.DateTimeField(_(u'Fecha de última modificación'),
            auto_now=True)

    #: Fecha de publicación del contenido
    published_at = models.DateTimeField(_(u'Fecha Publicación'),
            auto_now_add=True)

    class Meta:
        abstract = True

    def __unicode__(self):
        return self.name

    def save(self, *args, **kwargs):
        slug = slugify(self.name)
        model = self.__class__

        query = model.objects.filter(slug=slug)
        if not query.exists():
            self.slug = slug
        else:
            content = query.get()
            if self.id is None:
                self.slug = "%s-%s" % (slug, int(time()))
            elif self.id == content.id:
                self.slug = slug
            else:
                self.slug = "%s-%s" % (self.slug, self.id)
        return super(Content, self).save(*args, **kwargs)


from utils.utils import *
from models.utils import *

const_bnn_prior_parameters = {
    "prior_mu": 0.0,
    "prior_sigma": 1.0,
    "posterior_mu_init": 0.0,
    "posterior_rho_init": -3.0,
    "type": "Flipout",  # Flipout or Reparameterization
    "moped_enable": False,  # initialize mu/sigma from the dnn weights
    "moped_delta": 0.2,
}
from astropy.io import fits

def load_img(file):
    """
    加载图像，dat和fits均支持，不过仅支持CxHxW
    :param filename: 传入文件名，应当为CHW
    :return: 返回CHW的ndarray
    """
    if ".fits" in file:
        with fits.open(file) as hdul:
            return hdul[0].data.astype(np.float32)
    else:
        raise TypeError

def run():
    model = torch.load("/data/public/renhaoye/morphics/pth/model_148.pt")
    model.train()
    model.cuda()
    sample_mnist = torch.from_numpy(np.array(load_img("/data/public/renhaoye/morphics/dataset/in_decals/agmtn/138"
                                                      ".78548468501958_30.70684135654336.fits")))
    print(type(sample_mnist))
    sample_mnist = sample_mnist.to("cuda:0")
    pred_mnist, epi_mnist_norm, ale_mnist_norm = get_uncertainty_per_image(model, sample_mnist, T=25, normalized=True)
    print(pred_mnist)
    print(epi_mnist_norm)
    print(ale_mnist_norm)

if __name__ == '__main__':
    run()


# Source (A), Helper (B), Destination (C)

#user_input = input("Enter the stack values at source (A) (space separated): ")
#input_list = [int(i) for i in user_input.strip().split(' ')]
count = int(input("How many disks are there : "))

def TowerOfHanoi(n, A, B, C):

	if n == 0:
		return

	if n == 1:
		return

	TowerOfHanoi(n-1, A, C, B)
	TowerOfHanoi(n-1, B, A, C)

TowerOfHanoi(count, 's', 'h', 'd')


from maneuvers.driving.travel import Travel
from maneuvers.maneuver import Maneuver
from rlutilities.linear_algebra import vec3, norm
from rlutilities.simulation import Car, BoostPad, BoostPadState
from tools.drawing import DrawingTool
from tools.vector_math import distance

class PickupBoostPad(Maneuver):
    """Pickup a boostpad. Abort when picked up by someone else."""

    def __init__(self, car: Car, pad: BoostPad):
        super().__init__(car)
        self.pad = pad
        self.pad_was_active = self.pad.state == BoostPadState.Available

        self.travel = Travel(car, self.pad.position, waste_boost=True)

    def interruptible(self) -> bool:
        return self.travel.interruptible()

    def step(self, dt):
        # slow down when we're about to pick up the boost, so we can turn faster afterwards
        if distance(self.car, self.pad) < norm(self.car.velocity) * 0.2:
            self.travel.drive.target_speed = 1400

        self.travel.step(dt)
        self.controls = self.travel.controls

        # finish when someone picks up the pad
        if self.pad_was_active and self.pad.state == BoostPadState.Unavailable:
            self.finished = True
        self.pad_was_active = self.pad.state == BoostPadState.Available

        # finish when we picked the boost up but the previous condition somehow wasn't true
        if self.car.boost > 99 or distance(self.car, self.pad) < 100:
            self.finished = True

    def render(self, draw: DrawingTool):
        self.travel.render(draw)

        # draw timer if boost isn't available yet
        if self.pad and not self.pad.state == BoostPadState.Available:
            draw.color(draw.yellow)
            draw.string(self.pad.position + vec3(0, 0, 100), f"spawns in: {self.pad.timer:.1f}s")


import tensorflow as tf
import tensorflow_addons as tfa
from tensorboard.plugins.hparams import api as hp
from tensorflow.keras.layers.experimental.preprocessing import RandomFlip, RandomRotation, Resizing
from tensorflow.python.keras.layers import Dense

gpus = tf.config.experimental.list_physical_devices('GPU')
if gpus:
    try:
        # Currently, memory growth needs to be the same across GPUs
        for gpu in gpus:
            tf.config.experimental.set_memory_growth(gpu, True)
        logical_gpus = tf.config.experimental.list_logical_devices('GPU')
        print(len(gpus), "Physical GPUs,", len(logical_gpus), "Logical GPUs")
    except RuntimeError as e:
        # Memory growth must be set before GPUs have been initialized
        print(e)

# Parameter Inputs
DATA_DIR = "../../data/img/sahil_categories"
AUTOTUNE = tf.data.AUTOTUNE
NUM_CLASSES = 2
BATCH_SIZE = 32
image_height = 224
image_width = 224
IMAGE_SIZE = (image_width, image_height)
IMAGE_SIZE_DEPTH = (image_width, image_height, 3)
VALIDATION_SPLIT = 0.4
LABEL_MODE = 'categorical'
COLOR_MODE = 'rgb'
SEED = 42

# data augmentation layers
data_augmentation = tf.keras.Sequential([
    RandomFlip('horizontal'),
    RandomRotation(0.2),
])

def build_model(hparams=None):
    DROPOUT = 0.3
    NUM_UNITS = 32
    if hparams is not None:
        DROPOUT = hparams['HP_DROPOUT']
        NUM_UNITS = hparams['HP_NUM_UNITS']

    # Model configuration
    preprocess_input = tf.keras.applications.mobilenet_v2.preprocess_input
    # feature extraction into
    base_model = tf.keras.applications.MobileNetV2(input_shape=IMAGE_SIZE_DEPTH,
                                                   include_top=False,
                                                   weights='imagenet')
    base_model.trainable = False
    # batch data
    resize_layer = Resizing(224, 224, name='resize')

    # convert to single 1280 element
    global_average_layer = tf.keras.layers.GlobalAveragePooling2D()

    prediction_layer = tf.keras.layers.Dense(NUM_CLASSES, activation='softmax')

    inputs = tf.keras.Input(shape=(None, None, 3))
    x = resize_layer(inputs)
    x = data_augmentation(x)
    x = preprocess_input(x)
    x = base_model(x, training=False)
    x = global_average_layer(x)
    x = Dense(NUM_UNITS, activation='relu')(x)
    x = tf.keras.layers.Dropout(DROPOUT)(x)
    outputs = prediction_layer(x)
    model = tf.keras.Model(inputs, outputs)
    print(model.summary())
    return model, base_model

def compile_model(model, optimizer=None, loss=None, metrics=None):
    base_learning_rate = 0.0001
    optimizer = optimizer if optimizer is not None else tf.keras.optimizers.Adam(lr=base_learning_rate)
    loss = loss if loss is not None else 'categorical_crossentropy'
    metrics = metrics if metrics is not None else ['categorical_accuracy']
    model.compile(optimizer='sgd',
                  loss=tfa.losses.SigmoidFocalCrossEntropy(),
                  metrics=metrics)
    print(model.summary())

def return_model():
    model, _ = build_model()
    compile_model(model)
    return model

if __name__ == '__main__':
    return_model()


import requests
import streamlit as st

st.title('CyberPolice')
st.subheader("Sexual Harassment Detection System")

input_text = st.text_input('Text Input')

if st.button("Check"):
    if input_text is not None and len(input_text) > 0:
        res = requests.post(f"http://backend:8000/predict",
                            json={'input_text': input_text})
        result = res.json()
        print(res, result, type(res), type(result))
        # st.write(res, result, type(res), type(result))
        pred = result["confidence"]
        if pred>0.5:
            st.warning(result['CyberPolice'])
        else:
            st.success(result['CyberPolice'])
    else:
        st.error("Please provide text input for CyberPolice to check!")


import os
import cv2
import shutil
import numpy as np
from PIL import Image

'''
Image brightness enhancement/reduction
'''
def brightness(image, image_name, save_dir):
    image = Image.fromarray(image)
    brightness = 1 + np.random.randint(1, 9) / 10
    brightness_img = image.point(lambda p: p * brightness)

    save_path = os.path.join(save_dir, image_name + '_brightness.jpg')
    brightness_img = np.array(brightness_img)
    cv2.imwrite(save_path, brightness_img)
    print(save_path, 'saved')

def darkness(image, image_name, save_dir):
    darkness = np.random.randint(1, 9) / 10
    darkness_img = image * darkness

    save_path = os.path.join(save_dir, image_name + '_darkness.jpg')
    cv2.imwrite(save_path, darkness_img)
    print(save_path, 'saved')

def save_brightness_label(name, raw_label_path, label_save_dir):
    brightness_label = os.path.join(label_save_dir, name + "_brightness.txt")
    shutil.copyfile(raw_label_path, brightness_label)
    print(brightness_label, 'saved')

def save_darkness_label(name, raw_label_path, label_save_dir):
    darkness_label = os.path.join(label_save_dir, name + "_darkness.txt")
    shutil.copyfile(raw_label_path, darkness_label)
    print(darkness_label, 'saved')


import grpc

from bb8.backend.module_api import (Message, CollectedData, EventPayload,
                                    GetgRPCService, Resolve, SupportedPlatform,
                                    GetUserId, PureContentModule,
                                    ModuleTypeEnum)

GRPC_TIMEOUT = 5
MAX_KEYWORDS = 7
DEFAULT_N_ITEMS = 7

def properties():
    return {
        'id': 'ai.compose.content.core.content',
        'type': ModuleTypeEnum.Content,
        'name': 'Content',
        'description': '',
        'supported_platform': SupportedPlatform.All,
        'variables': [],
    }

def schema():
    return {
        'type': 'object',
        'required': ['mode'],
        'properties': {
            'mode': {
                'enum': [
                    'prompt',
                    'trending',
                    'recommend',
                    'search',
                    'get_content',
                    'list_by_source',
                ]
            },
            'n_items': {
                'type': 'integer',
                'minimum': 1,
                'maximum': 10
            },
            'query': {'type': 'string'},
        }
    }

def get_default_image(source):
    source_default_images = {
        'storm': 'http://i.imgur.com/j1Kqrj1.png',
        'yahoo_rss': 'http://i.imgur.com/Q2Yfylc.jpg',
    }
    compose_default_image = 'http://i.imgur.com/xa9wSAU.png'
    return source_default_images.get(source, compose_default_image)

class NewsInfo(object):
    """Interface for querying news content"""

    def __init__(self):
        pb2_module, addr = GetgRPCService('content')
        channel = grpc.insecure_channel('%s:%d' % addr)
        self._stub = pb2_module.ContentInfoStub(channel)
        self._pb2_module = pb2_module

    def trending(self, user_id, source_name=None, count=5):
        return self._stub.Trending(
            self._pb2_module.TrendingRequest(
                user_id=user_id,
                source_name=source_name,
                count=count),
            GRPC_TIMEOUT).entries

    def get_content(self, entry_link, char_offset=0, limit=320):
        cont = self._stub.GetContent(
            self._pb2_module.GetContentRequest(
                entry_link=entry_link,
                char_offset=char_offset,
                limit=limit),
            GRPC_TIMEOUT)
        return cont.content, cont.char_offset, cont.total_length

    def get_picture(self, entry_link, pic_index=0, unused_count=1):
        cont = self._stub.GetPicture(
            self._pb2_module.GetPictureRequest(
                entry_link=entry_link,
                pic_index=pic_index),
            GRPC_TIMEOUT)
        return cont.src, cont.alt, cont.pic_index

    def recommend(self, user_id, count=5):
        return self._stub.PersonalRecommend(
            self._pb2_module.RecommendRequest(
                user_id=user_id, count=count
            ), GRPC_TIMEOUT).entries

    def search(self, query, count=5):
        return self._stub.Search(
            self._pb2_module.SearchRequest(query=query, count=count),
            GRPC_TIMEOUT).entries

    def get_keywords(self, count=5):
        return self._stub.GetKeywords(
            self._pb2_module.GetKeywordsRequest(limit=count),
            GRPC_TIMEOUT).keywords

    def get_related_keywords(self, name, count=5):
        return self._stub.GetRelatedKeywords(
            self._pb2_module.GetRelatedKeywordsRequest(
                name=name, limit=count),
            GRPC_TIMEOUT).keywords

def add_quick_reply_keywords(news_info, message, show_related=False):
    """Install QuickReply keywords into message."""
    keywords = news_info.get_keywords(MAX_KEYWORDS)
    reply_kws = []
    if show_related:
        query_term = CollectedData.GetLast('query_term', '')
        related_kws = news_info.get_related_keywords(query_term, 3)

        reply_kws = [kw.name for kw in related_kws]
        for kw in keywords:
            if len(reply_kws) < MAX_KEYWORDS and kw.name not in reply_kws:
                reply_kws.append(kw.name)
    else:
        reply_kws += [kw.name for kw in keywords]

    for kw in reply_kws:
        message.add_quick_reply(Message.QuickReply(
            Message.QuickReplyType.TEXT, kw))

    message.add_quick_reply(Message.QuickReply(
        Message.QuickReplyType.TEXT, u'熱門新聞'))
    message.add_quick_reply(Message.QuickReply(
        Message.QuickReplyType.TEXT, u'搜尋'))

def render_cards(news_info, news):
    """Render cards given a list of new entries."""
    if not len(news):
        return [Message(u'找不到你要的新聞喔！')]

    m = Message()
    for n in news:
        image_url = (n.image_url if n.image_url != '' else
                     get_default_image(n.source))
        b = Message.Bubble(n.title,
                           image_url=image_url,
                           subtitle=n.description)
        b.add_button(Message.Button(
            Message.ButtonType.POSTBACK,
            u'在這讀', payload=EventPayload('GET_CONTENT', {
                'entry_link': n.link,
                'char_offset': 0,
                'pic_index': 1,
            }, False)))
        b.add_button(Message.Button(
            Message.ButtonType.WEB_URL, u'去網站讀',
            url=n.link))
        b.add_button(Message.Button(Message.ButtonType.ELEMENT_SHARE))
        m.add_bubble(b)

    add_quick_reply_keywords(news_info, m, True)
    return [m]

def run_get_content(news_info, variables, limit):
    try:
        event = variables['event']
        content, char_offset, total_length = news_info.get_content(
            event.value['entry_link'], event.value['char_offset'], limit)
        src, alt, pic_index = news_info.get_picture(
            event.value['entry_link'],
            event.value['pic_index'])
    except KeyError:
        return [Message(u'抱歉，有些東西出錯了，請再試一次！')]

    content_ended = char_offset == -1
    picture_ended = pic_index == -1
    all_ended = content_ended and picture_ended

    has_picture = src and alt
    has_content = content != ''

    progress = float(char_offset) / total_length * 100 \
        if char_offset >= 0 else 100.0

    msgs = []
    if has_content and not all_ended:
        m = Message(buttons_text=content)
        m.add_button(Message.Button(
            Message.ButtonType.POSTBACK,
            u'繼續讀 ({:.0f}%)'.format(progress),
            payload=EventPayload('GET_CONTENT', {
                'entry_link': event.value['entry_link'],
                'char_offset': char_offset,
                'pic_index': pic_index,
            }, False)))
        m.add_button(Message.Button(
            Message.ButtonType.WEB_URL, u'去網站讀',
            url=event.value['entry_link']))
        msgs.append(m)
    elif has_content:
        msgs.append(Message(content))

    if has_picture:
        src_msg = Message(image_url=src)
        if alt.strip():
            alt_msg = Message()
            b = Message.Bubble(alt, subtitle=' ')
            # Only append button to the last message, so only append if
            # content is empty
            if not has_content and not all_ended:
                b.add_button(Message.Button(
                    Message.ButtonType.POSTBACK,
                    u'繼續看圖 (文字已結束)',
                    payload=EventPayload('GET_CONTENT', {
                        'entry_link': event.value['entry_link'],
                        'char_offset': char_offset,
                        'pic_index': pic_index,
                    }, False)))
                b.add_button(Message.Button(
                    Message.ButtonType.WEB_URL, u'去網站讀',
                    url=event.value['entry_link']))
            alt_msg.add_bubble(b)
            msgs = [src_msg, alt_msg] + msgs
        else:
            msgs = [src_msg] + msgs

    if all_ended:
        m = Message(u'這則新聞讀完囉！')
        add_quick_reply_keywords(news_info, m, True)

        msgs.append(m)

    return msgs

@PureContentModule
def run(config, unused_user_input, env, variables):
    news_info = NewsInfo()
    n_items = config.get('n_items', DEFAULT_N_ITEMS)
    user_id = GetUserId()

    limit = 200
    if env['platform_type'] == SupportedPlatform.Line:
        limit = 160

    if config['mode'] == 'get_content':
        return run_get_content(news_info, variables, limit)

    if config['mode'] == 'list_by_source':
        source_name = Resolve(config['query_term'], variables)
        return render_cards(
            news_info,
            news_info.trending(user_id, source_name, n_items))

    elif config['mode'] == 'prompt':
        m = Message(u'想要知道什麼呢？今天這些字最夯！')
        add_quick_reply_keywords(news_info, m)
        return [m]

    elif config['mode'] == 'search':
        query_term = Resolve(config['query_term'], variables)
        return render_cards(
            news_info,
            (news_info.search(query_term, n_items)
             if query_term else news_info.trending(user_id)))

    return render_cards(news_info, news_info.trending(user_id))


"""
This module contains useful functions for the iterative tensor routines
and data type conversions
"""
import numpy as np
from functools import reduce
from ...core.structures import Tensor, TensorCPD, TensorTKD, TensorTT

def _select_base_function(base):
    """ Utility for creating arrays
    Parameters
    ----------
    base : str
        Id of base function.
        If not one from ``{"arange", "randn", "rand", "ones"}`` then `np.arange` will be used.
    Returns
    -------
        Numpy function for creating arrays
    """
    return {"arange": np.arange,
            "randn": np.random.randn,
            "rand": np.random.rand,
            "ones": np.ones}.get(base, np.arange)

def quick_tensor(shape, base="arange"):
    """ Simplified creation of generic tensor

    Parameters
    ----------
    shape : tuple
        Desired shape of the tensor
    base : str
        Id of base function that generates values for the tensor.
        If not one from ``{"arange", "randn", "rand", "ones"}`` then ``np.arange`` will be used.

    Returns
    -------
    tensor : Tensor

    Examples
    --------
        >>> from hottbox.utils.generation import quick_tensor
        >>> tensor = quick_tensor(shape=(2, 3, 4))
        >>> print(tensor)
            This tensor is of order 3 and consists of 24 elements.
            Sizes and names of its modes are (2, 3, 4) and ['mode-0', 'mode-1', 'mode-2'] respectively.
        >>> print(tensor.data)
            [[[ 0  1  2  3]
              [ 4  5  6  7]
              [ 8  9 10 11]]
             [[12 13 14 15]
              [16 17 18 19]
              [20 21 22 23]]]
        >>> tensor = quick_tensor(shape=(2, 3, 4), base="ones")
        >>> print(tensor)
            This tensor is of order 3 and consists of 24 elements.
            Sizes and names of its modes are (2, 3, 4) and ['mode-0', 'mode-1', 'mode-2'] respectively.
        >>> print(tensor.data)
            [[[1. 1. 1. 1.]
              [1. 1. 1. 1.]
              [1. 1. 1. 1.]]
             [[1. 1. 1. 1.]
              [1. 1. 1. 1.]
              [1. 1. 1. 1.]]]
    """
    size = reduce(lambda x, y: x * y, shape)
    create_ndarray = _select_base_function(base)
    array = np.reshape(create_ndarray(size), shape)
    tensor = Tensor(array=array)
    return tensor

def quick_tensorcpd(full_shape, rank, base="arange"):
    """ Simplified creation of generic tensor in kruskal form

    Parameters
    ----------
    full_shape : tuple
        Desired shape of the tensor when it is reconstructed.
        Values specify the number of rows of the factor matrices.
    rank : tuple
        Desired kruskal rank of the tensor. Specifies the number of columns for all factor matrices.
        In order to be consistent with the rest of ``hottbox`` should be in form of ``(value,)``
    base : str
        Id of base function that generates values for the components of kruskal tensor.
        If not one from ``{"arange", "randn", "rand", "ones"}`` then ``np.arange`` will be used.

    Returns
    -------
    tensor_cpd : TensorCPD

    Examples
    --------
        >>> from hottbox.utils.generation import quick_tensorcpd
        >>> tensor_cpd = quick_tensorcpd(full_shape=(3, 4, 5), rank=(2,), base="ones")
        >>> print(tensor_cpd)
            Kruskal representation of a tensor with rank=(2,).
            Factor matrices represent properties: ['mode-0', 'mode-1', 'mode-2']
            With corresponding latent components described by (3, 4, 5) features respectively.
        >>> tensor = tensor_cpd.reconstruct()
        >>> print(tensor)
            This tensor is of order 3 and consists of 60 elements.
            Sizes and names of its modes are (3, 4, 5) and ['mode-0', 'mode-1', 'mode-2'] respectively.
    """
    create_ndarray = _select_base_function(base)
    fmat_shapes = zip(full_shape, [rank[0] for _ in range(len(full_shape))])
    core_values = np.ones(rank[0])
    fmat = []
    for fmat_shape in fmat_shapes:
        size = reduce(lambda x, y: x * y, fmat_shape)
        fmat.append(np.reshape(create_ndarray(size), fmat_shape))
    tensor_cpd = TensorCPD(fmat=fmat, core_values=core_values)
    return tensor_cpd

def quick_tensortkd(full_shape, rank, base="arange"):
    """ Simplified creation of generic tensor in tucker form

    Parameters
    ----------
    full_shape : tuple
        Desired shape of the tensor when it is reconstructed.
        Values specify the number of rows of the factor matrices.
    rank : tuple
        Desired multi-linear rank of the tensor. Specifies the number of columns for all factor matrices.
        Should be of the same length as parameter ``full_shape``
    base : str
        Id of base function that generates values for the components of tucker tensor.
        If not one from ``{"arange", "randn", "rand", "ones"}`` then ``np.arange`` will be used.

    Returns
    -------
    tensor_tkd : TensorTKD

    Examples
    --------
        >>> from hottbox.utils.generation import quick_tensortkd
        >>> tensor_tkd = quick_tensortkd(full_shape=(5, 6, 7), rank=(2, 3, 4), base="ones")
        >>> print(tensor_tkd)
            Tucker representation of a tensor with multi-linear rank=(2,).
            Factor matrices represent properties: ['mode-0', 'mode-1', 'mode-2']
            With corresponding latent components described by (5, 6, 7) features respectively.
        >>> tensor = tensor_tkd.reconstruct()
        >>> print(tensor)
            This tensor is of order 3 and consists of 210 elements.
            Sizes and names of its modes are (5, 6, 7) and ['mode-0', 'mode-1', 'mode-2'] respectively.
    """
    create_ndarray = _select_base_function(base)
    fmat_shapes = zip(full_shape, rank)
    core_values = np.ones(rank)
    fmat = []
    for shape in fmat_shapes:
        size = reduce(lambda x, y: x * y, shape)
        fmat.append(np.reshape(create_ndarray(size), shape))
    tensor_tkd = TensorTKD(fmat=fmat, core_values=core_values)
    return tensor_tkd

def quick_tensortt(full_shape, rank, base="arange"):
    """ Simplified creation of generic tensor in tensor train form

    Parameters
    ----------
    full_shape : tuple
        Desired shape of the tensor when it is reconstructed.
    rank : tuple
        Desired tt rank of the tensor.
    base : str
        Id of base function that generates values for the components of tensor train tensor.
        If not one from ``{"arange", "randn", "rand", "ones"}`` then ``np.arange`` will be used.

    Returns
    -------
    tensor_tt : TensorTT

    Examples
    --------
        >>> from hottbox.utils.generation import quick_tensortt
        >>> tensor_tt = quick_tensortt(full_shape=(3, 4, 5), rank=(2, 3), base="ones")
        >>> print(tensor_tt)
            Tensor train representation of a tensor with tt-rank=(2, 3).
            Shape of this representation in the full format is (3, 4, 5).
            Physical modes of its cores represent properties: ['mode-0', 'mode-1', 'mode-2']
        >>> tensor = tensor_tt.reconstruct()
        >>> print(tensor)
            This tensor is of order 3 and consists of 60 elements.
            Sizes and names of its modes are (3, 4, 5) and ['mode-0', 'mode-1', 'mode-2'] respectively.
    """
    create_ndarray = _select_base_function(base)
    tt_ranks_l = rank[:-1]
    tt_ranks_r = rank[1:]
    number_of_middle_cores = len(tt_ranks_l)
    first_core_shape = (full_shape[0], rank[0])
    last_core_shape = (rank[-1], full_shape[-1])
    middle_cores_shape = [(tt_ranks_l[i], full_shape[i + 1], tt_ranks_r[i]) for i in range(number_of_middle_cores)]
    core_shapes = [first_core_shape] + middle_cores_shape + [last_core_shape]
    core_values = []
    for shape in core_shapes:
        size = reduce(lambda x, y: x * y, shape)
        core_values.append(np.reshape(create_ndarray(size), shape))
    tensor_tt = TensorTT(core_values=core_values)
    return tensor_tt


__author__ = 'yibeihuang'
class Node(object):
    def numIslands2(self, m, n, positions):
        """
        :type m: int
        :type n: int
        :type positions: List[List[int]]
        :rtype: List[int]
        """
        nodeset = dict()
        res = []
        for (i,j) in positions:
            cnt = 0
            node = self.makeset(Node(i,j))
            nodeset[(i,j)] = node
            for idx in (i-1,j),(i+1,j),(i,j-1),(i,j+1):
                if idx in nodeset:
                    x,y = idx
                    node1,node2 = nodeset[(i,j)], nodeset[(x,y)]
                    self.union(node1,node2)
            resdict = dict()
            for (i,j) in nodeset:
                parent = self.find(nodeset[(i,j)])
                if parent.data not in resdict:
                    resdict[parent.data]=1
                    cnt+=1
            res.append(cnt)
        return res

    def makeset(self, node):
        node.parent=node
        return node

    def union(self, node1, node2):
        p1, p2 = self.find(node1), self.find(node2)
        if p1==p2: return
        elif p1.rank>p2.rank:p2.parent=p1
        else:
            p1.parent = p2
            if p1.rank==p2.rank:p2.rank+=1

    def find(self, node):
        if node.parent==node:
            return node
        node.parent = self.find(node.parent)
        return node.parent

sol = Solution()
sol.numIslands2(3,3,[[0,0],[0,1],[1,2],[2,1]])


import numpy as np
from itertools import groupby
from collections import Counter
from bson.objectid import ObjectId
import math
###### START: Preparation #####

'''
The following code belongs to an deprecated calculation logic and is therefore commented out

'''

# def get_recurrence_chains(rec_mat_norm):
#     rec_chain = []
#     for row in rec_mat_norm:
#         chain = ' '
#         chain = chain.join(map(str, row))
#         chain = chain.replace(" ", "")
#         chain = chain.split("0")
#         chain = list(filter(None, chain))
#         rec_chain = rec_chain + chain

#     return rec_chain

# def get_diagonal_chains(rec_mat_norm):
#     diags = [rec_mat_norm[::1, :].diagonal(
#         i) for i in range(-rec_mat_norm.shape[0]+1, rec_mat_norm.shape[1])]

#     return diags

# def wordListToFreqDict(rec_chain):
#     freq = [rec_chain.count(p) for p in rec_chain]
#     return dict(list(zip(rec_chain, freq)))  # freqdict

# def sortFreqDict(freqdict):
#     freq = [(freqdict[key], key) for key in freqdict]
#     freq.sort()
#     freq.reverse()
#     return freq

# def get_frequency_of_data(freqdict):
#     result = []
#     for item in freqdict:
#         result.append((item[0], len(item[1])))
#     return result

# def clean_data(freqdict):
#     freqdict = [i for i in freqdict if i[1] == 1]
#     return freqdict

# def get_recurrence_freq(thrshld_mat):
#     rec_chains = get_recurrence_chains(thrshld_mat)  # GET RECURRENCE CHAINS
#     freqDict = wordListToFreqDict(rec_chains)
#     freqDict_sorted = sortFreqDict(freqDict)  # sorted
#     # Format: (Anzahl, Länge der Kette)
#     chain_freq = get_frequency_of_data(freqDict_sorted)

#     return chain_freq

# def get_recurrence_freq_diag(thrshld_mat):
#     rec_chains_diag = get_diagonal_chains(
#         thrshld_mat)  # GET DIAOGONAL RECURRENCE MATRIX
#     rec_chains_diag = get_recurrence_chains(
#         rec_chains_diag)  # GET RECURRENCE CHAINS

#     freqDict = wordListToFreqDict(rec_chains_diag)
#     freqDict_sorted = sortFreqDict(freqDict)  # sorted
#     # Format: (Anzahl, Länge der Kette)
#     chain_freq = get_frequency_of_data(freqDict_sorted)

#     return chain_freq

# def get_rr(chain_frequency):
#     rr_n = 0
#     # Hier müsste eine Anpassung vorgenommen werden, falls eine andere Matrix getestet werden soll.
#     rr_z = 5400**2
#     for item in chain_frequency:
#         rr_n += item[0]*item[1]

#     rr = rr_n / rr_z
#     return rr

# # req_chain-Format: [(Anzahl1, Länge1), (Anzahl2, Länge2),...]
# # det = diagonal recurrence chains
# # lam = vertical recurrence chains

# # Der Algorithmus ist unabhängig von der Art der Matrix, wonach keine Unterscheidung zwischen diagonaler Kette und vertikaler Kette erfolgt

# def get_det_lam(req_chain, rr):
#     det_lam_n = 0
#     for item in req_chain:
#         if(item[1] < 3):
#             continue
#         else:
#             det_lam_n += item[0]*item[1]

#     det_lam = det_lam_n / rr
#     return det_lam

# # req_chain-Format: [(Anzahl1, Länge1), (Anzahl2, Länge2),...]
# # Der Algorithmus ist unabhängig von der Art der Matrix, wonach keine Unterscheidung zwischen diagonaler Kette und vertikaler Kette erfolgt

# def get_l_tt(req_chain):
#     l_tt_z = 0
#     l_tt_n = 0
#     for item in req_chain:
#         if(item[1] < 3):
#             continue
#         else:
#             l_tt_z += item[0]*item[1]
#             l_tt_n += item[0]

#     l_tt = l_tt_z / l_tt_n

#     return l_tt

# def get_entr(chain_freq):
#     anzahl_ketten = sum(a for a, l in chain_freq)
#     entr = 0

#     for item in chain_freq:
#         if(item[1] < 3):
#             continue
#         else:
#             p = item[0] / anzahl_ketten
#             entr_p = p * np.log2(p)
#             entr += entr_p

#     entr = entr*(-1)

#     return entr

# def create_rqa(thrshld_mat):
#     req_chain = get_recurrence_freq(thrshld_mat)
#     req_chain_diag = get_recurrence_freq_diag(thrshld_mat)

#     rr = get_rr(req_chain)
#     det = get_det_lam(req_chain_diag, rr)
#     lam = get_det_lam(req_chain, rr)
#     l = get_l_tt(req_chain_diag)
#     tt = get_l_tt(req_chain)
#     entr = get_entr(req_chain_diag)
#     entr_vert = get_entr(req_chain)

#     rqa = {
#         "rr": rr,
#         "det": det,
#         "lam": lam,
#         "l": l,
#         "tt": tt,
#         "entr": entr,
#         "entr_vert": entr_vert
#     }

#     return rqa

# #################################### v2 #########################################

'''
Current calculation logic of all rqa-parameters
'''

def numpy_fillna(data):
    # Get lengths of each row of data
    lens = np.array([len(i) for i in data])

    # Mask of valid places in each row
    mask = np.arange(lens.max()) < lens[:, None]

    # Setup output array and put elements from data into masked positions
    out = np.zeros(mask.shape, dtype=data.dtype)
    out[mask] = np.concatenate(data)
    return out

def get_rqas(rp_thrsld, rps_collection, rp_id):
    rqa = {}
    rr_n = np.sum(rp_thrsld) - math.sqrt(2) * len(rp_thrsld)
    rr_z = len(rp_thrsld)**2
    rr = rr_n / rr_z

    # Insert rr to RP-ID
    query = {"_id": ObjectId(rp_id)}
    newvalues = {"$set": {"rr": rr}}
    rps_collection.update_one(query, newvalues)

    min_chain_length = 3

    zero_list = np.zeros((rp_thrsld.shape[0], 1))
    rp_thrsld_zeros = np.hstack((rp_thrsld, zero_list))
    x = list(np.array(rp_thrsld_zeros).flat)
    grouped = (list(g) for _, g in groupby(enumerate(x), lambda t: t[1]))
    vertical_chains = [(g[0][0], g[-1][0] + 1)
                       for g in grouped if len(g) >= min_chain_length]

    result_list = []
    lam_z = 0
    tt_n = len(vertical_chains)

    for item in vertical_chains:

        if x[item[0]] == 1:
            chain_length = item[1]-item[0]
            result_list.append(chain_length)

            lam_z += chain_length

        else:
            continue

    lam = lam_z / rr_n
    # Insert lam to RP-ID
    query = {"_id": ObjectId(rp_id)}
    newvalues = {"$set": {"lam": lam}}
    rps_collection.update_one(query, newvalues)

    tt = lam_z / tt_n
    # Insert tt to RP-ID
    query = {"_id": ObjectId(rp_id)}
    newvalues = {"$set": {"tt": tt}}
    rps_collection.update_one(query, newvalues)

    rqa["rr"] = rr
    rqa["lam"] = lam
    rqa["tt"] = tt

    entr = 0
    chain_length_list = dict(Counter(result_list))  # {length1, amount1, ...}

    for key in chain_length_list:

        p = chain_length_list[key] / tt_n
        entr_p = p * np.log2(p)
        entr += entr_p

    entr_v = abs(entr)
    rqa["entr-v"] = entr_v
    # Insert entr-v to RP-ID
    query = {"_id": ObjectId(rp_id)}
    newvalues = {"$set": {"entr-v": entr_v}}
    rps_collection.update_one(query, newvalues)

    ######## Diagonal RQA ##############

    diags = [rp_thrsld[::1, :].diagonal(
        i) for i in range(-rp_thrsld.shape[0]+1, rp_thrsld.shape[1])]
    diags_norm = numpy_fillna(np.asarray(diags))

    zero_list = np.zeros((np.asarray(diags_norm).shape[0], 1))
    rp_thrsld_zeros = np.hstack((diags_norm, zero_list))
    x = list(np.array(rp_thrsld_zeros).flat)
    grouped = (list(g) for _, g in groupby(enumerate(x), lambda t: t[1]))
    diagonal_chains = [(g[0][0], g[-1][0] + 1)
                       for g in grouped if len(g) >= min_chain_length]

    result_list = []
    det_z = 0
    l_n = len(diagonal_chains)

    for item in diagonal_chains:

        if x[item[0]] == 1:
            chain_length = item[1]-item[0]
            if chain_length == len(diags_norm[0]):
                continue
            else:
                result_list.append(chain_length)

                det_z += chain_length

        else:
            continue

    det = det_z / rr_n
    # Insert det to RP-ID
    query = {"_id": ObjectId(rp_id)}
    newvalues = {"$set": {"det": det}}
    rps_collection.update_one(query, newvalues)
    l = det_z / l_n
    # Insert l to RP-ID
    query = {"_id": ObjectId(rp_id)}
    newvalues = {"$set": {"l": l}}
    rps_collection.update_one(query, newvalues)

    rqa["det"] = det
    rqa["l"] = l

    entr = 0
    chain_length_list = dict(Counter(result_list))  # {length1, amount1, ...}

    for key in chain_length_list:

        p = chain_length_list[key] / l_n
        entr_p = p * np.log2(p)
        entr += entr_p

    rqa["entr"] = entr*(-1)
    # Insert entr to RP-ID
    query = {"_id": ObjectId(rp_id)}
    newvalues = {"$set": {"entr": entr}}
    rps_collection.update_one(query, newvalues)

    return rqa


'''
Author: daniel
Date: 2023-02-10 19:53:33
LastEditTime: 2023-08-06 21:43:02
LastEditors: daniel
Description: NYUD2 dataloader
FilePath: /Cerberus-main/dataloaders/datasets/nyud2.py
have a nice day
'''

from utils import *

from os.path import join,split,exists

import numpy as np

from tqdm import tqdm

import scipy.io as scio
# from dataloaders.datasets.nyud_geonet import *
from torchvision import transforms

import os

from utils.utils import *

class Nyud2:
    def __init__(self,
                path='/home/DISCOVER_summer2022/xusc/exp/Cerberus-main/data/nyud2',
                subset='NYU_origin',
                gen_edge = False):

        self.subset = subset
        self.path = join(path,subset)

        self.name_list= readtxt(join(self.path,'val.txt'))

        self.depths_path = join(self.path,'nyu_depths')
        self.images_path = join(self.path,'nyu_images')
        self.labels_path = join(self.path,'nyu_labels')
        self.normals_path = join(self.path,'nyu_normals')

        self.edge_path = join(self.path,'nyu_edges')
        self.depth_edge_path = join(self.path,'nyu_depth_edge_canny')
        self.normal_edge_path = join(self.path,'nyu_normal_edge_canny')

        make_dir(self.edge_path)
        make_dir(self.depth_edge_path)
        make_dir(self.normals_path)
        make_dir(self.normal_edge_path)

        #* the data need to crop
        #* 1. depth edge (canny); 2. image; 3.  normal edge (canny);
        #* 4. depth map; 5. normal  map
        #* target scale : [45:471, 41:601]

        self.cropped_path = join(self.path,'cropped')

        self.__depth_edge_path= join(self.cropped_path,'nyu_depth_edge_canny')
        self.__depth_edge_path2= join(self.cropped_path,'nyu_depth_edge')
        self.__image_path= join(self.cropped_path,'nyu_images')
        self.__normal_edge_path= join(self.cropped_path,'nyu_normal_edge_canny')
        self.__depth_path= join(self.cropped_path,'nyu_depths')
        self.__normal_path= join(self.cropped_path,'nyu_normals')

        self.__depth_edge_mat_path= join(self.cropped_path,'nyu_depth_edge_canny_mat')
        self.__depth_edge2_mat_path= join(self.cropped_path,'nyu_depth_edge_mat')
        self.__normal_edge_mat_path= join(self.cropped_path,'nyu_normal_edge_canny_mat')

        make_dir(self.__depth_edge_path)
        make_dir(self.__depth_edge_path2)
        make_dir(self.__depth_edge2_mat_path)

        make_dir(self.__image_path)
        make_dir(self.__normal_edge_path)
        make_dir(self.__depth_path)
        make_dir(self.__normal_path)
        make_dir(self.__depth_edge_mat_path)
        make_dir(self.__normal_edge_mat_path)

        if gen_edge:
            self.gen_edge_mp()
            self.gen_depth_edge_mp()
            # self.gen_normal_edge_mp()

            #* cropped data generation
            # self.gen_cropped_data()

        #* generate the normal map, crop the normal edge map of geonet and move them here actually.
        # self.geonet_loader = NYUD_GeoNet(split='val',root='/home/DISCOVER_summer2022/xusc/exp/Cerberus-main/data/nyud2')
        # self.gen_normal_mp()
        normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
        self.transformer = transforms.Compose([
                             transforms.ToTensor(),
                             normalize])  ## pre-process of pre-trained model of pytorch resnet-50

        # self.gen_mat_mp()

    '''
    description:  save  mat file for evaluation
    param {*} self
    param {*} file_name
    param {*} gt_map
    return {*}
    '''
    def save_as_mat(self,file_name,gt_map):

        scio.savemat(file_name,
            {'__header__': b'MATLAB 5.0 MAT-file, Platform: MACI64, Created on: Mon Feb 7 06:47:01 2023',
            '__version__': '1.0',
            '__globals__': [],
            'groundTruth': [{'Boundaries':gt_map}]
            }
        )

    def gen_mat(self,idx):

        image,depth_map,label,edge,depth_edge,normal_map,normal_edge,name =self.getitem(idx)
        self.save_as_mat(join(self.__depth_edge_mat_path,name.split('.')[0]+'.mat'),depth_edge)
        self.save_as_mat(join(self.__normal_edge_mat_path,name.split('.')[0]+'.mat'),normal_edge)

        imwrite('a.jpg',depth_edge)
        imwrite('b.jpg',normal_edge)

    def gen_mat_mp(self):
        # process_mp(self.gen_mat,range(self.__len__()),num_threads=256)
        process_mp(self.gen_mat,range(self.__len__()),num_threads=1)

    def gen_one_cropped_data(self,idx):

        def crop_save(path,src):

            if not exists(path):
                imwrite(path,src[45:471, 41:601])

        image,depth_map,label,edge,depth_edge,normal_map,normal_edge,name =self.__getitem__(idx)
        #*1.  save image
        crop_save(join(self.__image_path,name),image)

        #*2.  save depth edge
        crop_save(join(self.__depth_edge_path,name),depth_edge)

        #*3.  save normal edge
        crop_save(join(self.__normal_edge_path,name),normal_edge)

        #*4.  save  depth map
        crop_save(join(self.__depth_path,name),depth_map)

        #*5.  save normal map
        crop_save(join(self.__normal_path,name),normal_map)

    '''
    description:
    param {*} self
    return {*}
    '''
    def gen_cropped_data(self):
        process_mp(self.gen_one_cropped_data,range(self.__len__()),num_threads=256)

    '''
    description: generate one  normal map
    param {*} self
    param {*} idx
    return {*}
    '''
    def gen_one_normal(self,idx):

        # for idx,(sample,name) in tqdm(enumerate(geonet_loader)):
        sample,_=self.geonet_loader.__getitem__(idx)
        _,_,_,_,_,_,_,name=self.__getitem__(idx)

        # image,_,_,_,_,_,_,name=self.__getitem__(idx)
        matched_normal = convert_image_vertical((normal_reverse_process(sample['normals'])*255).astype(np.uint8))
        imwrite(join(self.normals_path,name),matched_normal)
        # imwrite('a.jpg',image)
        # imwrite('b.jpg',matched_normal)

    '''
    description: generate the normal map
    param {*} self
    return {*}
    '''
    def gen_normal_mp(self):
        process_mp(self.gen_one_normal,range(self.__len__()),num_threads=256)

    '''
    description:  gen one edge map
    param {*} self
    param {*} idx
    return {*}
    '''
    def gen_save_depth_edge(self,idx,depth_threshold = 2):

        # save_path =  join(self.depth_edge_path,self.name_list[idx])
        save_path =  join(self.__depth_edge_path2,self.name_list[idx])
        mat_save_path =  join(self.__depth_edge2_mat_path,self.name_list[idx].split('.')[0]+'.mat')

        if not  exists(save_path) :

            _,depth_map,_,edge_map,_,_,_,_=self.getitem_no_crop(idx)
            # image,depth,label,edge,depth_edge,normal_map,normal_edge,self.name_list[idx]

            #* dilation edge,
            # edge_map= dilation(edge_map,2)/255

            depth_edge =get_depth_edge_by_edge(depth_map,edge_map,depth_threshold=depth_threshold)*255

            # imwrite(save_path,depth_edge)
            #* save the cropped depth edge
            crpped = depth_edge[45:471, 41:601]
            imwrite(save_path,crpped)
            self.save_as_mat(mat_save_path,crpped)

            # imwrite('a.jpg',depth_map)
            # imwrite('b.jpg',edge_map)
            # imwrite('c.jpg',crpped)

    '''
    description:  gen one depth edge
    param {*} self
    param {*} idx
    return {*}
    '''
    def gen_save_depth_edge_by_canny(self,idx):

        save_path =  join(self.depth_edge_path,self.name_list[idx])

        if not  exists(save_path):
            _,depth,_,edge_map,_,_,_,_=self.__getitem__(idx)

            depth_edge = detect_edge(depth,15,55)
            #* 1. gen by edge map and local 5 X 5 depth value
            edge_map= dilation(edge_map,10)
            depth_edge[edge_map!=255]=0

            imwrite(save_path,depth_edge)

    def gen_depth_edge_mp(self):
        process_mp(self.gen_save_depth_edge,range(self.__len__()),num_threads=256)
        # process_mp(self.gen_save_depth_edge_by_canny,range(self.__len__()),num_threads=1)

    '''
    description:  gen one normal edge map
    param {*} self
    param {*} idx
    return {*}
    '''
    def gen_save_normal_edge_by_canny(self,idx):

        save_path =  join(self.normal_edge_path,self.name_list[idx])

        if not  exists(save_path) :
            _,_,_,edge_map,_,normal_map,_,_=self.__getitem__(idx)

            normal_edge = detect_edge(normal_map,50,150)

            #* 1. gen by edge map and local 5 X 5 depth value
            # edge_map= dilation(edge_map,2)
            # normal_edge[edge_map!=255]=0
            imwrite(save_path,normal_edge)

            # imwrite('a.jpg',normal_edge)
            # imwrite('b.jpg',edge_map)

    '''
    description: generate the normal map
    param {*} self
    return {*}
    '''
    def gen_normal_edge_mp(self):
        # process_mp(self.gen_one_normal,range(self.__len__()),num_threads=256)
        process_mp(self.gen_save_normal_edge_by_canny,range(self.__len__()),num_threads=256)

    '''
    description:  gen one edge map
    param {*} self
    param {*} idx
    return {*}
    '''
    def gen_save_edge(self,idx):
        save_path =  join(self.edge_path,self.name_list[idx])

        if not  exists(save_path) :
            label = imread(join(self.labels_path,self.name_list[idx]),gray=True)
            edge_map=get_edge_map_from_label(label)
            imwrite(save_path,edge_map*255)

    '''
    description:  generate edge multi thread
    param {*} self
    return {*}
    '''
    def gen_edge_mp(self):
        process_mp(self.gen_save_edge,range(self.__len__()),num_threads=256)

    def __len__(self):
        return len(self.name_list)

    def getitem_no_crop(self,idx):

        # return self.getitem_PIL(idx)
        depth = imread(join(self.depths_path,self.name_list[idx]),gray=True)
        image = imread(join(self.images_path,self.name_list[idx]))
        label = imread(join(self.labels_path,self.name_list[idx]),gray=True)
        edge = imread(join(self.edge_path,self.name_list[idx]),gray=True)

        depth_edge = imread(join(self.depth_edge_path,self.name_list[idx]),gray=True)
        normal_map = imread(join(self.normals_path,self.name_list[idx]))

        normal_edge  = imread(join(self.normal_edge_path,self.name_list[idx]),gray=True)

        return image,depth,label,edge,depth_edge,normal_map,normal_edge,self.name_list[idx]

    def __getitem__(self,idx):

        # return self.getitem_PIL(idx)
        image = imread(join(self.__image_path,self.name_list[idx]))
        depth = imread(join(self.__depth_path,self.name_list[idx]),gray=True)

        #* no cropped ========================================================
        label = imread(join(self.labels_path,self.name_list[idx]),gray=True)
        edge = imread(join(self.edge_path,self.name_list[idx]),gray=True)
        #* ==================================================================

        depth_edge = imread(join(self.__depth_edge_path,self.name_list[idx]),gray=True)
        normal_map = imread(join(self.__normal_path,self.name_list[idx]))
        normal_edge  = imread(join(self.__normal_edge_path,self.name_list[idx]),gray=True)

        # return image,depth,label,edge,depth_edge,normal_map,normal_edge,self.name_list[idx]
        # return self.transformer(image),depth,label,edge,depth_edge,normal_map,normal_edge,self.name_list[idx].split('.')[0]
        return self.transformer(image),self.name_list[idx].split('.')[0]

    def getitem(self,idx):

        # return self.getitem_PIL(idx)
        image = imread(join(self.__image_path,self.name_list[idx]))
        depth = imread(join(self.__depth_path,self.name_list[idx]),gray=True)

        #* no cropped ========================================================
        label = imread(join(self.labels_path,self.name_list[idx]),gray=True)
        edge = imread(join(self.edge_path,self.name_list[idx]),gray=True)
        #* ==================================================================

        depth_edge = imread(join(self.__depth_edge_path,self.name_list[idx]),gray=True)
        normal_map = imread(join(self.__normal_path,self.name_list[idx]))
        normal_edge  = imread(join(self.__normal_edge_path,self.name_list[idx]),gray=True)

        return image,depth,label,edge,depth_edge,normal_map,normal_edge,self.name_list[idx]

    def getitem_PIL(self,idx):

        image = imread_PIL(join(self.__image_path,self.name_list[idx]))
        depth = imread_PIL(join(self.__depth_path,self.name_list[idx]),gray=True)

        #* no cropped ========================================================
        label = imread_PIL(join(self.labels_path,self.name_list[idx]),gray=True)
        edge = imread_PIL(join(self.edge_path,self.name_list[idx]),gray=True)
        #* ==================================================================

        depth_edge = imread_PIL(join(self.__depth_edge_path,self.name_list[idx]),gray=True)
        normal_map = imread_PIL(join(self.__normal_path,self.name_list[idx]))
        normal_edge  = imread_PIL(join(self.__normal_edge_path,self.name_list[idx]),gray=True)

        return image,depth,label,edge,depth_edge,normal_map,normal_edge,self.name_list[idx]

if __name__ == "__main__":
    Nyud2(gen_edge=True)
    # Nyud2(gen_edge=False)


from threading import Thread
import os
from other_modules.decorators import count_run_time
######database
from ..main import dtb,tdtb,ldtb

from ...meilisearch.news import news_index,add_news_meili
from ...redis.post import MultiMinimumPost

#start
#########################################database#####################################
#cre_data
def ndb(value):

  tag_count = topic_count("count")
  tag_count["value"] += 1
  pos = tag_count["value"]
  value['position'] = pos
  update_topic_count("count",tag_count)

  for key in value["tags"]:
    topic = topic_count(key)
    topic["value"] += 1
    topic["position"].insert(0,pos)
    update_topic_count(key,topic)

  #insert multi database
  dtb.insert_one(value)
  minimum_data(value)
  #add_news_meili(value)

def minimum_data(element:dict):
  ele = {}
  ele["position"] = element["position"]
  ele["name"] = element["name"]
  ele["title"] = element["title"]
  ele["description"] = element["description"]
  ele["slide_show_link"] = element["slide_show_link"]
  ele["thumbnail_link"] = element["thumbnail_link"]

  ldtb.insert_one(ele)
  print(" ")
  print("insert minimum element done")
  print(ele)
  print(" ")

#take_data
def take_ndb(key,value):
  tests = dtb.find_one( { '{}'.format(key): value } )
  if tests:
    return tests
  else:
    return False

#update_data
def update_ndb(pos,value):
  global dtb
  dtb.update_one({ 'position': pos },  {'$set':value} )

#count

def topic_count(key:str):
  tests = tdtb.find_one( { 'name': key } )
  return tests

def update_topic_count(key,value):
  tdtb.update_one({"name":key},{'$set':value})

#update element
def update_element(pos:int,key:str,value):
  dtb.update_one({"position":pos},{'$set':{'{}'.format(key) : value }})

################################################### page process
#tag find
def position_show(pos_start:int,pos_end:int):
  element = dtb.find({ 'position': {'$gt':pos_start-1,'$lt':pos_end+1} }).sort('position',-1)

  value = []
  for ele in element:
    value.append(ele)

  return value

#find element in post list
@count_run_time
def find_pos(pos_list:list):
  value = []
  #print("before post list:"+ str(pos_list))
  pos_list = list(dict.fromkeys(pos_list))
  pos_list, value = MultiMinimumPost(pos_list)
  #print("after post list:"+ str(pos_list))
  if pos_list != []:
    element = ldtb.find({"position": { '$in': pos_list }  })
    for ele in element:
      value.append(ele)

  MultiMinimumPost.set_multi_minimum_post(value)
  return value

##################3 sync with meili
'''
#sync data with mongodb
'''
def sync_meili_mongo():
  elements = dtb.find()
  for element in elements:
    ele = None
    ele = {}
    ele["id"] = element["position"]
    ele["name"] = element["name"]
    ele["title"] = element["title"]
    ele["description"] = element["description"]
    ele["thumbnail_link"] = element["thumbnail_link"]
    ele["tags"] = element["tags"],

    news_index.add_documents(ele)

#sync_meili_mongo()