#C1
print("C2-----------------------------------------------")
def is_larger(x,y):
    if x>y:
        return True
    elif y>=x:
        return False
    else:
        pass

print ( is_larger (2 , -1))

#C2
print("C3-----------------------------------------------")
def letter_grade (n):
    if n>100 or n<0:
        return None
    elif n >=90:
        return "A"
    elif n >=80:
        return "B"
    elif n >=70:
        return "C"
    elif n >=60:
        return "D"
    else:
        return "E"

print ( letter_grade (80) )

#C3
print("C4-----------------------------------------------")
def list_sum(list):
    sum = 0.0
    for num in list:
        sum += num
    return sum

print(list_sum ([]))

print("C5-----------------------------------------------")
def minmax_in_list(alist):
    for passnum in range(len(alist)-1,0,-1):
        for i in range(passnum):
            if alist[i]>alist[i+1]:
                temp = alist[i]
                alist[i] = alist[i+1]
                alist[i+1] = temp
    if len(alist)>0:
        small = alist[0]
        big = alist[-1]
        return small, big
    else:
        return None, None

print(minmax_in_list ([1 ,2 ,3 ,4 ,5]))

print("C6-----------------------------------------------")
def is_palindrome(num):
    num = str(num)
    if num == str(num)[::-1]:
        return True
    else:
        return False

print(is_palindrome (1))

print("PS1-----------------------------------------------")
def check_value(n1, n2, n3, x):
    if x > n1 and x>n2 and x<n3:
        return True
    else:
        return False

print(check_value (1 ,4 ,8 ,7))
print(check_value (1 ,4 ,5 ,7))

print("PS2-----------------------------------------------")
def temp_convert (unit, num):
    if unit == "F":
        f = num*float(9)/5 + 32
        return f
    elif unit == "C":
        c = (num-32)*float(5)/9
        return c
    else:
        return None

print("PS3-----------------------------------------------")
def get_even_list(list):
    new_list = []
    for item in list:
        if item % 2 ==0:
            new_list.append(item)
    return new_list

print(get_even_list ([11 ,22 ,31 ,41 ,52]))

print("PS4-----------------------------------------------")
def is_prime(num):
    if num == 0 or num == 1:
        return False
    for i in range(2, num):
        if (num % i) == 0:
            return False
    return True

print(is_prime (13))

print("PS5-----------------------------------------------")

import math
def approx_ode(h,t0,y0,tn):
    if tn < h/2:
        return y0
    else:
        cal = approx_ode(h, t0, y0, tn-h)
        res = cal + h*f(tn-h, cal)
        return res

######### Ignore code below this line ######################################
def f(t, y):
    return 3.0+math.exp(-t)-0.5*y

print(approx_ode(0.1, 0, 1, 3))
print(approx_ode(0.1, 0, 1, 4))
print(approx_ode(0.1, 0, 1, 5))


from gophic.tk.common import *

class ResourceViewer(tk.Text):
  """Displays a Resource instance."""

  def __init__(self, master, *args, **kwargs):
    """Registers all style tags and initializes the widget."""
    tk.Text.__init__(self, master, *args, **kwargs)
    self.links = {}
    self.resource = None

    self.config(state="disabled")

    def onLinkClick(e):
      for tag in self.tag_names("current"):
        if tag[:5] == "link-":
          self.links[tag](e)

    self.tag_config("link", foreground="blue", underline=1)
    self.tag_bind("link", "<Enter>", lambda e: self.config(cursor="hand2"))
    self.tag_bind("link", "<Leave>", lambda e: self.config(cursor="xterm"))
    self.tag_bind("link", "<Button-1>", onLinkClick)

    self.tag_config("error", foreground="red")

  def link(self, url, search=False):
    """Register a link. Returns a tuple of text tags."""
    def callback(e):
      if search:
        query = simpledialog.askstring("Search query", "Enter a search query string",
          parent=gophic.tk.main)
        if query:
          url.query = query
      gophic.tk.main.navigate(url, force=True)

    tag = "link-{}".format(len(self.links))
    self.links[tag] = callback
    return "link", tag

  def insert(self, *args, **kwargs):
    self.config(state="normal")
    tk.Text.insert(self, *args, **kwargs)
    self.config(state="disabled")

  def delete(self, *args, **kwargs):
    self.config(state="normal")
    tk.Text.delete(self, *args, **kwargs)
    self.config(state="disabled")

  def render(self):
    """Renders the current resource."""
    self.delete(1.0, "end")
    self.links = {}
    if self.resource and hasattr(self.resource, "render"):
      self.resource.render(self)


from kol1testy import runtests
# Piotr Rzadkowski
# Algorytm bazuje na funkcji partition. Dla kazdej kopii p elementowego przedzialu tablicy sprawdza, ktory elementy bylby
# k-ty najwiekszy a nastepnie go zwraca. Element zostaje dodany do sumy. Sytuacja jest powtarzana dla kazdego elementu dostajemy wynik.
# Poniewaz przedzialow jest w zaokragleniu w gore n, znajdywanie k-tej najwiekszej liczby w przedziale p elementowym jest liniowe
# Algorytm ma zlozonosc O(n*p)

def partition(A, l, r):
    x = A[r]

    i = l-1
    for j in range(l, r):
        if A[j] <= x:
            i += 1
            A[i], A[j] = A[j], A[i]
    A[i+1], A[r] = A[r], A[i+1]
    return i+1

def find_k_el(A, k):
    n = len(A)
    # k = n-k
    l = 0
    r = n-1
    while True:
        q = partition(A, l, r)
        if q == k:
            return A[q]
        elif q < k:
            l = q+1
        else:
            r = q-1

def ksum(T, k, p):
    n = len(T)
    s = 0
    fin = p-k
    for i in range(n-p+1):
        val = find_k_el(T[i:p+i], fin)
        print(val)
        s += val
    return s

T = [5, 8, 3, 1, 2, 8, 5, 4, 3, 2, 1]
p = 4
k = 2
print(ksum(T,k,p))
# zmien all_tests na True zeby uruchomic wszystkie testy
# runtests(ksum, all_tests=True)


Daniel_Radcliffe = ["Man", "Brun", "Brun", "Daniel Radcliffe"]
Rupert_Grint = ["Man", "Röd", "Blå", "Rupert Grint"]
Emma_Watson = ["Kvinna", "Brun", "Brun", "Emma Watson"]
Selena_Gomez = ["Kvinna", "Brun", "Brun", "Selena Gomez"]
Samuel_Olsson = ["Man", "Brun", "Grön", "Samuel Olsson"]
Donald_Trump = ["Man", "Blond", "Grön", "Donald Trump"]
Stefan_Löfven = ["Man", "Brun", "Blå", "Stefan Löfven"]
Ulf_Kristersson = ["Man", "Svart", "Blå", "Ulf Kristersson"]
Jan_Björklund = ["Man", "Grå", "Blå", "Jan Björklund"]
Kändisar = [Daniel_Radcliffe, Rupert_Grint, Emma_Watson, Selena_Gomez, Samuel_Olsson, Donald_Trump, Stefan_Löfven, Ulf_Kristersson, Jan_Björklund]
Liknade_kändisar = ""

print("Ange kön:")
Kön = str(input())

print("Ange hårfärg:")
Hårfärg = str(input())

print("Ange ögonfärg:")
Ögonfärg = str(input())

for Kändisar in Kändisar:
    if Kändisar[0] == Kön:
        if Kändisar[1] == Hårfärg:
            if Kändisar[2] == Ögonfärg:
                Liknade_kändisar += Kändisar[3] + ", " # Kändisar som har samma egenskap inom någon av variablerna läggs till i listan med liknande kändisar.

if Liknade_kändisar == "":
    print("Du liknar ingen kändis.")
else:
    print("Egenskaperna matchar med: " + Liknade_kändisar + ".") # Om man har minst en egenskap gemensam med en kändis skrivs kändisens eller kändisarnas namn.


from management.utils import validate_and_get_key
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView

from api.common.pagination import StandardResultsSetPagination
from .proxy import PrincipalProxy
from ..permissions.principal_access import PrincipalAccessPermission

USERNAMES_KEY = "usernames"
EMAIL_KEY = "email"
SORTORDER_KEY = "sort_order"
VALID_SORTORDER_VALUE = ["asc", "desc"]
MATCH_CRITERIA_KEY = "match_criteria"
VALID_MATCH_VALUE = ["partial", "exact"]
STATUS_KEY = "status"
VALID_STATUS_VALUE = ["enabled", "disabled", "all"]
ADMIN_ONLY_KEY = "admin_only"
VALID_BOOLEAN_VALUE = ["true", "false"]
USERNAME_ONLY_KEY = "username_only"

class PrincipalView(APIView):
    """Obtain the list of principals for the tenant."""

    """
    @api {get} /api/v1/principals/   Obtain a list of principals
    @apiName getPrincipals
    @apiGroup Principal
    @apiVersion 1.0.0
    @apiDescription Obtain a list of principals

    @apiHeader {String} token User authorization token

    @apiParam (Query) {Number} offset Parameter for selecting the start of data (default is 0).
    @apiParam (Query) {Number} limit Parameter for selecting the amount of data (default is 10).

    @apiSuccess {Object} meta The metadata for pagination.
    @apiSuccess {Object} links  The object containing links of results.
    @apiSuccess {Object[]} data  The array of results.

    @apiSuccessExample {json} Success-Response:
        HTTP/1.1 200 OK
        {
            'meta': {
                'count': 2
            }
            'links': {
                'first': /api/v1/principals/?offset=0&limit=10,
                'next': None,
                'previous': None,
                'last': None
            },
            'data': [
                            {
                                "username": "jsmith",
                                "email": "jsmith@company.com"
                            },
                            {
                                "username": "ksmith",
                                "email": "ksmith@company.com"
                            }
                        ]
        }

    """

    permission_classes = (PrincipalAccessPermission,)

    def get(self, request):
        """List principals for account."""
        user = request.user
        path = request.path
        query_params = request.query_params
        default_limit = StandardResultsSetPagination.default_limit
        usernames_filter = ""
        options = {}
        try:
            limit = int(query_params.get("limit", default_limit))
            offset = int(query_params.get("offset", 0))
            options["sort_order"] = validate_and_get_key(query_params, SORTORDER_KEY, VALID_SORTORDER_VALUE, "asc")
            options["status"] = validate_and_get_key(query_params, STATUS_KEY, VALID_STATUS_VALUE, "enabled")
        except ValueError:
            error = {
                "detail": "Values for limit and offset must be positive numbers.",
                "source": "principals",
                "status": str(status.HTTP_400_BAD_REQUEST),
            }
            errors = {"errors": [error]}
            return Response(status=status.HTTP_400_BAD_REQUEST, data=errors)

        previous_offset = 0
        if offset - limit > 0:
            previous_offset = offset - limit

        resp, usernames_filter = self.users_from_proxy(user, query_params, options, limit, offset)

        status_code = resp.get("status_code")
        response_data = {}
        if status_code == status.HTTP_200_OK:
            data = resp.get("data", [])
            if isinstance(data, dict):
                count = data.get("userCount")
                data = data.get("users")
            elif isinstance(data, list):
                count = len(data)
            else:
                count = None
            response_data["meta"] = {"count": count}
            response_data["links"] = {
                "first": f"{path}?limit={limit}&offset=0{usernames_filter}",
                "next": f"{path}?limit={limit}&offset={offset + limit}{usernames_filter}",
                "previous": f"{path}?limit={limit}&offset={previous_offset}{usernames_filter}",
                "last": None,
            }
            response_data["data"] = data
        else:
            response_data = resp
            del response_data["status_code"]

        return Response(status=status_code, data=response_data)

    def users_from_proxy(self, user, query_params, options, limit, offset):
        """Format principal request for proxy and return prepped result."""
        proxy = PrincipalProxy()
        usernames = query_params.get(USERNAMES_KEY)
        email = query_params.get(EMAIL_KEY)
        match_criteria = validate_and_get_key(query_params, MATCH_CRITERIA_KEY, VALID_MATCH_VALUE, "exact")
        options["username_only"] = validate_and_get_key(query_params, USERNAME_ONLY_KEY, VALID_BOOLEAN_VALUE, "false")

        if not usernames and not email:
            options["admin_only"] = validate_and_get_key(query_params, ADMIN_ONLY_KEY, VALID_BOOLEAN_VALUE, "false")
            resp = proxy.request_principals(
                account=user.account, org_id=user.org_id, limit=limit, offset=offset, options=options
            )
            return resp, ""
        proxyInput = {}
        resp = None
        if usernames:
            principals = usernames.split(",")
            if match_criteria != "partial":
                resp = proxy.request_filtered_principals(
                    principals,
                    account=user.account,
                    org_id=user.org_id,
                    limit=limit,
                    offset=offset,
                    options=options,
                )
                usernames_filter = f"&usernames={usernames}"
                return resp, usernames_filter
            else:
                proxyInput["principalStartsWith"] = principals[0]
        if email:
            if match_criteria == "partial":
                proxyInput["emailStartsWith"] = email
            else:
                proxyInput["primaryEmail"] = email
        resp = proxy.request_principals(
            account=user.account, org_id=user.org_id, input=proxyInput, limit=limit, offset=offset, options=options
        )
        return resp, ""


from django.contrib import messages
from django.contrib.auth import login
from django.contrib.auth.decorators import login_required
from django.db import transaction
from django.db.models import Count
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse_lazy
from django.utils.decorators import method_decorator
from django.views.generic import CreateView, ListView, UpdateView

from ..decorators import customer_required
from ..cart import Cart
from ..forms import CustomerSignUpForm, OrderCreateForm, CartAddProductForm
from ..models import User, Product, Category, OrderItem

class CustomerSignUpView(CreateView):
    model = User
    form_class = CustomerSignUpForm
    template_name = 'registration/signup_form.html'

    def get_context_data(self, **kwargs):
        kwargs['user_type'] = 'customer'
        return super().get_context_data(**kwargs)

    def form_valid(self, form):
        user = form.save()
        login(self.request, user)
        return redirect('customer:product_list')

@login_required
@customer_required
def homey(request):
    context = locals ()
    return render(request, 'multiusers/customer/homey.html', context)

@login_required
@customer_required
def product_list(request, category_slug=None):
    category = None
    categories = Category.objects.all()
    products = Product.objects.filter(available=True)
    if category_slug:
        category = get_object_or_404(Category, slug=category_slug)
        products = Product.objects.filter(category=category)

    context = {
        'category': category,
        'categories': categories,
        'products': products,
    }
    return render(request, 'multiusers/customer/list.html', context)

def product_detail(request, id, slug):
    product = get_object_or_404(Product, id=id, slug=slug, available=True)
    cart_product_form = CartAddProductForm()
    context = {
        'product': product,
        'cart_product_form': cart_product_form
    }
    return render(request, 'multiusers/customer/product_detail.html', context)

def order_create(request):
    cart = Cart(request)
    if request.method == 'POST':
        form = OrderCreateForm(request.POST)
        if form.is_valid():
            order = form.save()
            for item in cart:
                OrderItem.objects.create(
                    order=order,
                    product=item['product'],
                    price=item['price'],
                    quantity=item['quantity']
                )
            cart.clear()
        return render(request, 'multiusers/customer/created.html', {'order': order})
    else:
        form = OrderCreateForm()
    return render(request, 'multiusers/customer/create.html', {'form': form})

def cart_add(request, product_id):
    cart = Cart(request)  # create a new cart object passing it the request object
    product = get_object_or_404(Product, id=product_id)
    form = CartAddProductForm(request.POST)
    if form.is_valid():
        cd = form.cleaned_data
        cart.add(product=product, quantity=cd['quantity'], update_quantity=cd['update'])
    return redirect('cart:cart_detail')

def cart_remove(request, product_id):
    cart = Cart(request)
    product = get_object_or_404(Product, id=product_id)
    cart.remove(product)
    return redirect('cart:cart_detail')

def cart_detail(request):
    cart = Cart(request)
    for item in cart:
        item['update_quantity_form'] = CartAddProductForm(initial={'quantity': item['quantity'], 'update': True})

    return render(request, 'cart/detail.html', {'cart': cart})


__author__ = 'young'

from numpy import *
from scipy.ndimage import filters
from scipy.misc import imsave
import cv2
import cv2.cv as cv
import numpy as np
import os

NEXT,PREV,FIRST_CHILD,PARENT=0,1,2,3
MAX_CARD_AREA = 50000
MIN_CARD_AREA = 10000
ELEMENT = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3))
ELEMENT_ELLIPSE = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3))

scale = 1
delta = 0
ddepth = cv2.CV_16S

def show(img):
    cv2.imshow("img", img)
    cv2.waitKey(0)

# thresholding grey scaled img
def preprocess(img):
    img = cv2.cvtColor(img, cv2.cv.CV_RGB2GRAY)
    img = cv2.GaussianBlur(img, (3, 3), 0)
    img = cv2.adaptiveThreshold(img, 255, 1, 1, 7, 2)
    img = cv2.morphologyEx(img, cv2.MORPH_CLOSE, ELEMENT_ELLIPSE, iterations=1)
    return img

# thresholding grey scaled img
def preprocess1(img):
    img = cv2.cvtColor(img, cv2.cv.CV_RGB2GRAY)
    img = cv2.GaussianBlur(img, (3, 3), 0)
    img = cv2.adaptiveThreshold(img, 255, 1, 1, 11, 2)
    img = cv2.dilate(img, ELEMENT)
    # Gradient-X
    grad_x = cv2.Sobel(img,ddepth,1,0,ksize = 3, scale = scale, delta = delta,borderType = cv2.BORDER_DEFAULT)
    #grad_x = cv2.Scharr(gray,ddepth,1,0)

    # Gradient-Y
    grad_y = cv2.Sobel(img,ddepth,0,1,ksize = 3, scale = scale, delta = delta, borderType = cv2.BORDER_DEFAULT)
    #grad_y = cv2.Scharr(gray,ddepth,0,1)

    abs_grad_x = cv2.convertScaleAbs(grad_x)   # converting back to uint8
    abs_grad_y = cv2.convertScaleAbs(grad_y)

    img = cv2.addWeighted(abs_grad_x,0.5,abs_grad_y,0.5,0)
    #dst = cv2.add(abs_grad_x,abs_grad_y)
    show(img)
    return img

# find rectangles from a thresholded image
def find_rectangles(thresh):
    contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    areas = [ cv2.contourArea(c) for c in contours]
    indexes = range(len(contours))
    items = sorted(zip(indexes, areas, contours, hierarchy[0]), key=lambda x:x[0], reverse=True)
    return card_filter(items)

def card_filter(items):
    results = {}
    for index, area, contour, hierarchy in items:
        if area > MIN_CARD_AREA and area < MAX_CARD_AREA:
            #results.append([index, area, contour, hierarchy])
            results[index]=[index, area, contour, hierarchy]

    to_del = []
    for k, v in results.items():
        _, a, c, h = v
        if h[PARENT] in results:
            if a/results[h[PARENT]][1] > 0.9:
                to_del.append(h[PARENT])
            else:
                to_del.append(k)

    for i in set(to_del):
        results.pop(i)
    return [c for i,a,c,h in results.values()]

# @param: img - preprocced img
def extract_cards(img):
    pass

def draw_rectangle(img, contour):
    x,y,w,h = cv2.boundingRect(contour)
    cv2.rectangle(img, (x,y),(x+w,y+h),(0,255,0),1)

def draw_rect(img):
    thresh = preprocess(img)
    contours,hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    hierarchy = hierarchy[0]

    for component in zip(contours, hierarchy):
        currentContour = component[0]
        currentHierarchy = component[1]
        if not currentHierarchy[FIRST_CHILD] < 0:
            draw_rectangle(currentContour)
    show(img)

def test_draw_contour(filename):
    img_orig = cv2.imread(filename)
    for c in find_rectangles(preprocess(img_orig)):
        draw_rectangle(img_orig, c)

    show(img_orig)
    cv2.imwrite(os.path.join(os.path.dirname(filename), "contours_" + os.path.basename(filename)), img_orig)

def extract_cards(filename):
    img_orig = cv2.imread(filename)
    contours = find_rectangles(preprocess(img_orig))
    corners = [np.int0(cv2.cv.BoxPoints(cv2.minAreaRect(c))) for c in contours]
    card_corners=[sorted_corners(c) for c in corners if sortable(c)]
    cards = []
    for i, c1 in enumerate(card_corners):
        norm_card = np.array([[0, 0],[99,0],[99,139],[0,139]], dtype = np.float32)
        transform_matrix = cv2.getPerspectiveTransform(c1, norm_card)
        warp = cv2.warpPerspective(img_orig, transform_matrix, (100,140))
        cards.append(warp)
    return cards

def sorted_corners(corners):
    center = corners.sum(0) * 0.25

    top, bot = [], []
    for point in corners:
        if point[1] < center[1]:
            top.append(point)
        else:
            bot.append(point)

    if top[0][0] > top[1][0]:
        tl = top[1]
        tr = top[0]
    else:
        tl = top[0]
        tr = top[1]

    if bot[0][0] > bot[1][0]:
        bl = bot[1]
        br = bot[0]
    else:
        bl = bot[0]
        br = bot[1]

    return array([tl,tr,br,bl], dtype = np.float32)

def sortable(corners):
    center = corners.sum(0) * 0.25

    top, bot = [], []
    for point in corners:
        if point[1] < center[1]:
            top.append(point)
        else:
            bot.append(point)
    return len(top) == len(bot)

def main(filename, output_dir):
    cards = extract_cards(filename)
    for i, card in enumerate(cards):
        cv2.imwrite(os.path.join(output_dir,"full_card%02d.jpg" % i), card)

if __name__ == '__main__':
    main('../raw_images/desk_full1.jpg', '../cards')
    #test_draw_contour('../raw_images/desk_full1.jpg')
    #test_draw_contour('../raw_images/desk.jpg')


# from notebooks.opencv_install.opencv_contrib.modules.dnn_objdetect.scripts.pascal_preprocess import rescale
import PIL
import numpy
from numpy.core.fromnumeric import argmax
import pandas as pd
import open3d as o3d
import random
import math
import re
import h5py
import io
import multiprocessing

# from multiprocessing import Pool
from multiprocessing import get_context

# multiprocessing.set_start_method('spawn') #Fork does not play nice with h5py!
# Reference: https://pythonspeed.com/articles/python-multiprocessing/

import numpy as np
import cupy as cp
import os

from tqdm import tqdm

from deco import concurrent, synchronized
from tqdm.utils import RE_ANSI

import siampose.data.objectron.data_transforms
import siampose.data.objectron.sequence_parser
import siampose.data.utils
import siampose.geometry as geo

from siampose.data.objectron.dataset import iou
from siampose.data.objectron.dataset import box

from google.protobuf import text_format

# The annotations are stored in protocol buffer format.
from siampose.data.objectron.schema import annotation_data_pb2 as annotation_protocol

# The AR Metadata captured with each frame in the video
from siampose.data.objectron.schema import (
    a_r_capture_metadata_pb2 as ar_metadata_protocol,
)

from PIL import Image, ImageDraw

EDGES = (
    [1, 5],
    [2, 6],
    [3, 7],
    [4, 8],  # lines along x-axis
    [1, 3],
    [5, 7],
    [2, 4],
    [6, 8],  # lines along y-axis
    [1, 2],
    [3, 4],
    [5, 6],
    [7, 8],  # lines along z-axis
)

FACES = np.array(
    [
        [5, 6, 8, 7],  # +x on yz plane
        [1, 3, 4, 2],  # -x on yz plane
        [3, 7, 8, 4],  # +y on xz plane = top
        [1, 2, 6, 5],  # -y on xz plane = bottom
        [2, 4, 8, 6],  # +z on xy plane = front
        [1, 5, 7, 3],  # -z on xy plane
    ]
)

BOTTOM_POINTS = [1, 2, 6, 5]

use_cupy = True

def get_center_ajust(result_bbox, projected_center):
    cx_result = (result_bbox[0] + result_bbox[2]) / 2
    cy_result = (result_bbox[1] + result_bbox[3]) / 2
    adjust_x = projected_center[0] - cx_result
    adjust_y = projected_center[1] - cy_result
    adjust_x_rel = adjust_x / (result_bbox[2] - result_bbox[0])
    adjust_y_rel = adjust_y / (result_bbox[3] - result_bbox[1])
    return adjust_x_rel, adjust_y_rel

def estimate_object_center_in_query_image(
    query_intrinsics, query_bbox, points_2d_px_result
):
    cx = (query_bbox[0] + query_bbox[2]) / 2
    cy = (query_bbox[1] + query_bbox[3]) / 2
    result_bbox = geo.get_bbox(points_2d_px_result, 360, 480)
    projected_center = points_2d_px_result[0]
    adjust_x_rel, adjust_y_rel = get_center_ajust(result_bbox, projected_center)
    adjust_x_px = adjust_x_rel * (query_bbox[2] - query_bbox[0])
    adjust_y_px = adjust_y_rel * (query_bbox[3] - query_bbox[1])
    cx = cx + adjust_x_px
    cy = cy + adjust_y_px
    b = (cx - query_intrinsics[1, 2]) / query_intrinsics[1, 1]
    a = (cy - query_intrinsics[0, 2]) / query_intrinsics[0, 0]
    return cx, cy, a, b

def align_box_with_plane(points3d, plane_normal_query, plane_normal_result):
    box_rotation = geo.rotation_matrix_from_vectors(
        plane_normal_query, plane_normal_result
    )
    # plane_normal_query, plane_normal_result, plane_center_query, plane_center_result
    points_3d_axis = np.dot(points3d - points3d[0], box_rotation) + points3d[0]
    return points_3d_axis

def get_scale_factor(query_bbox, points3d_scaled, intrinsics, width=360, height=480):
    points2d_px_result = geo.project_3d_to_2d(points3d_scaled, intrinsics)
    # points2d_px_query = geo.project_3d_to_2d(points_3d_query, intrinsics)
    result_bbox = geo.get_bbox(points2d_px_result, width, height)
    # query_bbox = geo.get_bbox(points2d_px_query, width, height)
    scale = geo.get_bbox_area(query_bbox) / geo.get_bbox_area(result_bbox)
    return scale

def get_smooth_scale_factor(query_bbox, points3d_scaled, intrinsics, alpha):
    factor = get_scale_factor(query_bbox, points3d_scaled, intrinsics)
    return (alpha + factor - 1) / alpha

def get_bounding_box(idx, match_idx, experiment, adjust_scale=False):
    points_2d_result, points_3d_result = experiment.get_points(match_idx, train=True)
    points_2d_px_result = geo.points_2d_to_points2d_px(points_2d_result, 360, 480)
    points_2d_query, _ = experiment.get_points(idx, train=False)
    points_2d_px_query = geo.points_2d_to_points2d_px(points_2d_query, 360, 480)
    plane_center_query, plane_normal_query = experiment.get_plane(idx, train=False)
    plane_center_result, plane_normal_result = experiment.get_plane(
        match_idx, train=True
    )
    result_bbox = geo.get_bbox(points_2d_px_result, 360, 480)
    # query_camera = experiment.get_camera(idx, train=False)
    query_intrinsics = experiment.get_intrinsics(idx, train=False)
    query_intrinsics = geo.scale_intrinsics(query_intrinsics, 0.25, 0.25)
    result_bbox = geo.get_bbox(points_2d_px_result, 360, 480)
    query_bbox = geo.get_bbox(points_2d_px_query, 360, 480)
    cx, cy, a, b = estimate_object_center_in_query_image(
        query_intrinsics, query_bbox, points_2d_px_result
    )
    center_ray = np.array([a, b, -1])
    points_3d_axis = align_box_with_plane(
        points_3d_result, plane_normal_query, plane_normal_result
    )
    obj_radius = geo.get_dist_from_plane(
        plane_normal_result, plane_center_result, points_3d_axis[0]
    )
    points_3d_result_snapped = geo.snap_to_plane(
        points_3d_axis, plane_normal_query, plane_center_query, center_ray, obj_radius
    )
    if adjust_scale:
        scale = get_smooth_scale_factor(
            query_bbox, points_3d_result_snapped, query_intrinsics, 2
        )
        points3d_scaled = points_3d_result_snapped
        for i in range(0, 4):
            # print(scale, obj_radius)
            obj_radius = geo.get_dist_from_plane(
                plane_normal_query, plane_center_query, points3d_scaled[0]
            )
            points3d_scaled = geo.snap_to_plane(
                geo.scale_3d_bbox(points3d_scaled, scale),
                plane_normal_query,
                plane_center_query,
                center_ray,
                obj_radius=obj_radius * scale,
            )
            scale = get_smooth_scale_factor(
                query_bbox, points3d_scaled, query_intrinsics, 2
            )
            # print(i, get_iou_between_bbox(np.array(points_3d_query), np.array(points3d_scaled)))
        return points3d_scaled
    return points_3d_result_snapped

def create_objectron_bbox_from_points(points, color=(0, 0, 0)):
    assert len(color) == 3
    # EDGES = (
    #    [1, 5], [2, 6], [3, 7], [4, 8],  # lines along x-axis
    #    [1, 3], [5, 7], [2, 4], [6, 8],  # lines along y-axis
    #    [1, 2], [3, 4], [5, 6], [7, 8]   # lines along z-axis
    # )
    pcd = o3d.geometry.PointCloud()
    pcd = o3d.geometry.PointCloud()
    pcd.points = o3d.utility.Vector3dVector(points)
    lineset = o3d.geometry.LineSet.create_from_point_cloud_correspondences(
        pcd, pcd, EDGES
    )
    colors = np.array(color * len(lineset.lines)).reshape(len(lineset.lines), 3)
    lineset.colors = o3d.utility.Vector3dVector(colors)
    return lineset

BOTTOM_POINTS = [1, 2, 6, 5]

def get_match_aligned_points(
    idx: int,
    match_idx: int,
    info_df: pd.DataFrame,
    train_info_df: pd.DataFrame,
    ground_truth=False,
):
    """Get 3D IoU for a specific query image, using the kth neighbor.

    Returns:
        [type]: [description]
    """
    assert type(match_idx) == int
    points2d_train, points3d_train = get_points(train_info_df, match_idx)
    points2d_valid, points3d_valid = get_points(info_df, idx)

    valid_image = Image.open(info_df.iloc[idx]["filepath_full"])
    train_image = Image.open(train_info_df.iloc[match_idx]["filepath_full"])
    points2d_valid_px = geo.points_2d_to_points2d_px(
        points2d_valid, valid_image.width, valid_image.height
    )
    points2d_train_px = geo.points_2d_to_points2d_px(
        points2d_train, train_image.width, train_image.height
    )
    valid_bbox = geo.get_bbox(points2d_valid_px, valid_image.width, valid_image.height)
    train_bbox = geo.get_bbox(points2d_train_px, train_image.width, train_image.height)
    points3d_train_rotated, _ = geo.align_with_bbox_3d(
        points3d_train, train_bbox, valid_bbox
    )
    if ground_truth:
        return np.array(points3d_train_rotated), np.array(points3d_valid)
    else:
        return np.array(points3d_train_rotated), np.array(points3d_train)

def get_objectron_bbox_colors():
    bbox_point_colors = np.zeros((9, 3))

    for bottom_point in BOTTOM_POINTS:
        bbox_point_colors[bottom_point] = np.array([1, 0, 0])
    bbox_point_colors[0] = np.array([0, 0, 1])
    return o3d.utility.Vector3dVector(bbox_point_colors)

def fix_idx(idx):
    if type(idx) is not int and type(idx) is not numpy.ndarray:
        idx = int(idx)  # Just make sure this is the right
    return idx

def visualize(points3d_query1, points3d_results1, points3d_results2):
    """Small visualisation helper. Interface will change!"""

    pcd_results1 = o3d.geometry.PointCloud()
    pcd_results2 = o3d.geometry.PointCloud()
    # points3d_train_results1 = points3d_results1
    # points3d_train_rotated, points3d_train_aligned = align_with_bbox_3d(points3d_train, train_bbox, valid_bbox)
    pcd_results1.points = o3d.utility.Vector3dVector(points3d_results1)
    pcd_results2.points = o3d.utility.Vector3dVector(points3d_results2)

    # pcd_train_aligned.points = o3d.utility.Vector3dVector(points3d_train_aligned)

    pcd_valid = o3d.geometry.PointCloud()
    pcd_valid.points = o3d.utility.Vector3dVector(points3d_query1)

    vis = o3d.visualization.Visualizer()
    vis.create_window()
    bbox_3d_results1 = pcd_results1.get_oriented_bounding_box()
    bbox_3d_results2 = pcd_results2.get_oriented_bounding_box()
    bbox_3d_valid = pcd_valid.get_oriented_bounding_box()
    # bbox_3d.create_from_point_cloud_poisson(pcd_train)
    bbox_3d_results1.color = [0, 0, 255]
    bbox_3d_results2.color = [255, 0, 0]
    vis.add_geometry(bbox_3d_results1)
    vis.add_geometry(bbox_3d_results2)
    vis.add_geometry(bbox_3d_valid)
    vis.add_geometry(pcd_results1)
    vis.add_geometry(pcd_results2)
    vis.add_geometry(pcd_valid)

    print(bbox_3d_results1.extent, bbox_3d_results1.center)
    print(bbox_3d_valid.extent, bbox_3d_valid.center)

    vis.run()
    ctr = vis.get_view_control()
    pinhole_parameters = ctr.convert_to_pinhole_camera_parameters()
    vis.destroy_window()
    # pinhole_parameters.intrinsic
    # vis.draw_geometries()
    return

def get_match_snapped_points(
    idx,
    match_idx,
    info_df,
    train_info_df,
    ground_truth=False,
    rescale=True,
    align_axis=True,
):
    assert type(match_idx) == int
    plane_center, plane_normal = get_plane(info_df, idx)
    points2d, points3d = get_points(info_df, idx)
    points3d_result_rotated, points3d_result = get_match_aligned_points(
        idx, match_idx, info_df, train_info_df, ground_truth=ground_truth
    )
    snapped, intersect = geo.snap_box_to_plane(
        points3d_result_rotated, plane_normal, plane_center, align_axis=align_axis
    )

    result = snapped
    if rescale:
        points2d_result, _ = get_points(train_info_df, match_idx)
        # points3d_result = np.array(points3d_result)
        camera = get_camera(info_df, idx)
        intrinsics = get_intrinsics(camera)
        intrinsics = geo.scale_intrinsics(intrinsics, 0.25, 0.25)
        points2d_px = geo.project_3d_to_2d(snapped, intrinsics)
        dest_bbox = geo.get_bbox(points2d_px, 360, 480)

        points2d_valid, points3d_valid = get_points(info_df, idx)

        valid_image = Image.open(info_df.iloc[idx]["filepath_full"])
        points2d_valid_px = geo.points_2d_to_points2d_px(
            points2d_valid, valid_image.width, valid_image.height
        )
        valid_bbox = geo.get_bbox(
            points2d_valid_px, valid_image.width, valid_image.height
        )
        scale_x, scale_y = geo.get_scale_factors(dest_bbox, valid_bbox)
        scale_factor = (scale_x + scale_y) / 2

        # print(scale_factor)
        fixed_point = snapped[0]
        snapped_rotated = snapped.copy()
        # scale_factor = 1.2
        snapped_rotated = (snapped_rotated - fixed_point) * scale_factor + fixed_point
        snapped_rotated, intersect = geo.snap_box_to_plane(
            snapped_rotated, plane_normal, plane_center
        )
        result = snapped_rotated

    return result, points3d_result

def get_iou_between_bbox(points_train, points_valid):
    try:
        v_rotated = np.array(points_train)
        v_valid = np.array(points_valid)
        w_rotated = box.Box(vertices=v_rotated)
        w_valid = box.Box(vertices=v_valid)
        loss = iou.IoU(w_rotated, w_valid)
        return float(loss.iou())
    except:
        print("Error computing IoU!")
        return 0

def get_iou(
    idx: int,
    embeddings: np.array,
    info_df: pd.DataFrame,
    train_embeddings: np.array,
    train_info_df: pd.DataFrame,
    symmetric=False,
    rescale=False,
    k=0,
    show=False,
    compute_aligned=False,
    ground_plane=True,
    align_axis=True,
):
    """Get 3D IoU for a specific query image, using the kth neighbor.

    Args:
        idx (int): Query index in meta dataframe.
        embeddings (np.array): Query embeddings.
        info_df (pd.DataFrame): Query embeddings metadata.
        train_embeddings (np.array): Trainin set embeddings. Will be used for lookup.
        train_info_df (pd.DataFrame): Training set embeddings metadata.
        k (int, optional): kth neighbor to use as result.. Defaults to 0.
        show (bool, optional): Visualize the result in 3D. Defaults to False.

    Returns:
        [type]: [description]
    """
    # @concurrent
    match_idx = find_match_idx(idx, embeddings, train_embeddings, k)
    if ground_plane:
        points3d_processed, points3d_valid = get_match_snapped_points(
            idx,
            match_idx,
            info_df,
            train_info_df,
            ground_truth=True,
            rescale=rescale,
            align_axis=align_axis,
        )
    else:
        points3d_processed, points3d_valid = get_match_aligned_points(
            idx, match_idx, info_df, train_info_df, ground_truth=True
        )

    # if show:
    #    visualize(points3d_valid, points3d_train_rotated, points3d_train_aligned)
    iou_value = get_iou_between_bbox(points3d_valid, points3d_processed)
    best_iou = iou_value
    if symmetric:
        for angle in np.arange(5, 360, 5):
            theta = (angle / 180) * np.pi
            pivoted = geo.rotate_bbox_around_its_center(points3d_processed, theta)
            iou_at_theta = get_iou_between_bbox(pivoted, points3d_valid)
            if iou_at_theta > best_iou:
                best_iou = iou_at_theta
        # _get_iou.wait()
    return best_iou, match_idx

def get_iou_rotated(points3d_processed, points3d_valid, initial_iou):
    """Get the IoU metric for a symmetric object by rotating it around its axis.

    Args:
        points3d_processed (np.array): Result Bounding box
        points3d_valid (np.array): Query Bounding box
        initial_iou (float): Initial IoU when the object is not rotated.

    Returns:
        float: Best IoU obtained while rotating the object around its axis.
    """
    best_iou = initial_iou
    for angle in np.arange(5, 360, 5):
        theta = (angle / 180) * np.pi
        pivoted = geo.rotate_bbox_around_its_center(points3d_processed, theta)
        iou_at_theta = get_iou_between_bbox(pivoted, points3d_valid)
        if iou_at_theta > best_iou:
            best_iou = iou_at_theta
    return best_iou

def find_match_idx(
    idx, query_embeddings: np.ndarray, train_embeddings: np.ndarray, k=0, score=False
):
    """Find the nearest neighbor of a single query embedding in the test set in the training set.

    Args:
        idx (int): Index in the test set.
        query_embeddings (np.ndarray): Test set embeddings.
        train_embeddings (np.ndarray): Train set embeddings.
        k (int, optional): kth neighbor to use. Defaults to 0.

    Returns:
        int: Match index in the train set.
    """
    global use_cupy
    idx = fix_idx(idx)
    lib = cp
    if not use_cupy:
        lib = np

    similarity = lib.dot(query_embeddings[idx].T, train_embeddings)
    if k != 0:
        best_matches = lib.argsort(-similarity)
        match_idx = best_matches[k]
    else:
        match_idx = lib.argmin(-similarity)
    if not score:
        return int(match_idx)
    else:
        return int(match_idx), float(similarity[match_idx])

def find_all_match_idx(query_embeddings: np.ndarray, train_embeddings: np.ndarray, k=0):
    """Find all matches for the test set in the training set at the sametime, using cupy.

    This is solely for optimisation purpose in order to get the code to run faster on machines
    with GPU.

    Args:
        query_embeddings (np.ndarray): Test set embeddings.
        train_embeddings (np.ndarray): Train set embeddings.
        k (int, optional): [description]. Defaults to 0.

    Raises:
        ValueError: The case where "k!=0" is not yet implemeted.

    Returns:
        [type]: [description]
    """
    global use_cupy
    print("Using GPU to compute matches!")

    if k != 0:
        # best_matches = cp.argsort(-cp.dot(query_embeddings.T,train_embeddings))
        # match_idx = best_matches[k]
        raise ValueError("The case where k is not 0 must be implemented.")
    else:
        match_idxs = []
        query_chunk_size = 1024
        train_chunk_size = 65536 * 2
        for i in tqdm(range(0, math.ceil(len(query_embeddings) / query_chunk_size))):
            query_start = i * query_chunk_size
            query_end = query_start + query_chunk_size
            if query_end > len(query_embeddings):
                query_end = len(query_embeddings)
            cuda_query_embeddings = cp.asarray(query_embeddings[query_start:query_end])

            matches = []
            scores = []
            best_match_idx_chunk_score = np.zeros((query_end - query_start, 1))
            best_match_idx_chunk = np.zeros(
                (query_end - query_start, 1), dtype=np.uint64
            )
            for j in range(0, math.ceil(train_embeddings.shape[1] / train_chunk_size)):
                train_start = j * train_chunk_size
                train_end = train_start + train_chunk_size
                if train_end > train_embeddings.shape[1]:
                    train_end = train_embeddings.shape[1]
                cuda_train_embeddings = cp.asarray(
                    train_embeddings[:, train_start:train_end]
                )
                similarity = cp.dot(cuda_query_embeddings, cuda_train_embeddings)
                match_idx_chunk = cp.argmax(similarity, axis=1).get()
                similarity = similarity.get()
                match_idx_chunk_score = np.take_along_axis(
                    similarity, np.expand_dims(match_idx_chunk, axis=1), axis=1
                )
                match_idx_chunk += train_start
                best_match_idx_chunk = np.where(
                    match_idx_chunk_score > best_match_idx_chunk_score,
                    np.expand_dims(match_idx_chunk, axis=1),
                    best_match_idx_chunk,
                ).astype(np.uint64)
                best_match_idx_chunk_score = np.where(
                    match_idx_chunk_score > best_match_idx_chunk_score,
                    match_idx_chunk_score,
                    best_match_idx_chunk_score,
                )

                # if use_cupy:
                # match_idx_chunk=match_idx_chunk.get()

                matches.append(match_idx_chunk)
            match_idxs += best_match_idx_chunk.squeeze().tolist()
        return match_idxs

def describe_intrinsics(intrinsics: np.array):
    """Describe the intrinsics matrix in their common names.

    Args:
        intrinsics (np.array): Intrinsics
    """
    alpha_x = intrinsics[0, 0]
    alpha_y = intrinsics[1, 1]
    center_x = intrinsics[0, 2]
    center_y = intrinsics[1, 2]
    return float(alpha_x), float(alpha_y), float(center_x), float(center_y)

# embeddings = None
# info_df = None
# train_embeddings = None
# train_info_df = None
experiment = None

args = None
all_match_idxs = None
import argparse
import time

def get_iou_mp(
    idx: int,  # , symmetric=False, rescale=False,
    # k=0, show=False, compute_aligned=False, ground_plane=True,
):
    """Get 3D IoU for a specific query image, using the kth neighbor.

    Args:
        idx (int): Query index in meta dataframe.
        embeddings (np.array): Query embeddings.
        info_df (pd.DataFrame): Query embeddings metadata.
        train_embeddings (np.array): Trainin set embeddings. Will be used for lookup.
        train_info_df (pd.DataFrame): Training set embeddings metadata.
        k (int, optional): kth neighbor to use as result.. Defaults to 0.
        show (bool, optional): Visualize the result in 3D. Defaults to False.

    Returns:
        [type]: [description]
    """

    global args, experiment, all_match_idxs
    experiment.load_hdf5_file()  # Just make sure the hdf5 file is not loader prior to forking.
    category = experiment.get_category(idx, train=False)

    # all_match_idxs = find_match_idx(idx, embeddings, train_embeddings,0)
    match_idx = all_match_idxs[idx]
    if args.random_bbox:
        match_idx = random.randint(0, len(experiment.train_info_df) - 1)
    if args.random_bbox_same:
        match_idx = random.sample(
            list(experiment.train_info_df.query(f"category=='{category}'").index), 1
        )
        match_idx = match_idx[0]

    # if args.legacy:
    #    if args.ground_plane:
    #        points3d_processed, points3d_valid = get_match_snapped_points(idx, match_idx, experiment.info_df, train_info_df, ground_truth=True, rescale=args.rescale, align_axis=not args.no_align_axis)
    #    else:
    #        points3d_processed, points3d_valid = get_match_aligned_points(idx, match_idx, experiment.info_df, train_info_df, ground_truth=True)
    # else:
    _, points3d_valid = experiment.get_points(idx, train=False)
    points3d_processed = get_bounding_box(idx, match_idx, experiment, adjust_scale=True)
    # if show:
    #    visualize(points3d_valid, points3d_train_rotated, points3d_train_aligned)
    iou_value = get_iou_between_bbox(points3d_valid, points3d_processed)
    best_iou = iou_value
    if args.symmetric:
        if category == "cup" or category == "bottle":
            best_iou = get_iou_rotated(points3d_processed, points3d_valid, best_iou)
        # _get_iou.wait()
    return best_iou, idx, match_idx

class ExperimentHandlerFile:
    def __init__(self, experiment: str = None, test=False):
        self.info_df = None
        self.train_info_df = None
        self.hdf5_dataset = None
        self.hdf5_test_dataset = None
        self.test = test
        if experiment:
            self.read_experiment(experiment, test)
        self.source_image_width = 1440
        self.source_image_height = 1920

    def read_experiment(self, experiment: str, test: bool):
        """Read the output of a SimSiam experiment folder. (Embeddings and metadata)

        Args:
            experiment (str): Output folder location

        Returns:
            tuple: validation embeddings, validation meta data, train embeddings, train meta data
        """
        global use_cupy
        load_fn = cp.load
        if not use_cupy:
            load_fn = np.load

        info_prefix = ""
        if test:
            info_prefix = "test_"
            print(
                "Loading experiment with test set instead of validation set embeddings!"
            )
        embeddings = load_fn(f"{experiment}/{info_prefix}embeddings.npy")
        if embeddings.shape[1] > embeddings.shape[0]:
            embeddings = embeddings.T
        info = numpy.load(f"{experiment}/{info_prefix}info.npy")
        assert info.shape[0] == 2
        train_new_filename = f"{experiment}/train_embeddings.npy"
        train_old_filename = f"{experiment}/training_embeddings.npy"
        if os.path.exists(train_new_filename):
            train_embeddings = load_fn(train_new_filename)
        else:
            train_embeddings = load_fn(train_old_filename)
        train_info = numpy.load(f"{experiment}/train_info.npy")
        assert train_info.shape[0] == 2

        # lines = content
        self.init_experiment(embeddings, info, train_embeddings, train_info)
        try:
            if not self.test:
                with open(f"{experiment}/train_sequences.txt", "r") as f:
                    train_sequences_t = f.read().split("\n")
                    valid_sequences_g = sorted(
                        list((self.info_df["sequence_uid"].unique()))
                    )
                    for valid_sequence in valid_sequences_g:
                        if valid_sequence in train_sequences_t:
                            raise ValueError(
                                f"The validation sequence {valid_sequence} was part of the training set!"
                            )
        except FileNotFoundError:
            print(
                f"Warning, unable to find {experiment}/train_sequences.txt.\n We will not be able to make sure there is no overlap between training and validation!"
            )

    def load_hdf5_file(self):
        if self.hdf5_dataset is None:
            self.hdf5_dataset = h5py.File(
                "/home/raphael/datasets/objectron/extract_s5_raw.hdf5", "r"
            )
        if self.test and self.hdf5_test_dataset is None:
            self.hdf5_test_dataset = h5py.File(
                "/home/raphael/datasets/objectron/extract_s5_raw_test.hdf5", "r"
            )

    def init_experiment(self, embeddings, info, train_embeddings, train_info):
        info_df = pd.DataFrame(info.T)
        train_info_df = pd.DataFrame(train_info.T)
        info_df_columns = {0: "category_id", 1: "uid"}
        train_info_df = train_info_df.rename(columns=info_df_columns)
        info_df = info_df.rename(columns=info_df_columns)
        if "hdf5" in train_info_df.iloc[0][1]:
            self.mode = "hdf5"
            self.hdf5_dataset = None
        else:
            self.mode = "raw"
        self.parse_info_df(info_df)
        self.parse_info_df(train_info_df, subset="train")
        assert train_embeddings.shape[0] == embeddings.shape[1]
        self.embeddings = embeddings
        self.train_embeddings = train_embeddings
        self.info_df = info_df
        self.train_info_df = train_info_df

    def _pick_hdf5_dataset(self, train):
        if not self.test:
            return self.hdf5_dataset
        if not train and self.test:
            return self.hdf5_test_dataset
        if train:
            return self.hdf5_dataset
        raise ValueError("We should get here!")

    def get_points(self, idx: int, train=False):
        if self.mode == "raw":
            return self._raw_get_points(idx, train)
        elif self.mode == "hdf5":
            category, sequence, image_id = self._hdf5_parse_uid(idx, train)
            hdf5_dataset = self._pick_hdf5_dataset(train)
            image_idx = list(hdf5_dataset[category][sequence]["IMAGE_ID"]).index(
                image_id
            )
            return hdf5_dataset[category][sequence]["POINT_2D"][image_idx].reshape(
                9, 3
            ), hdf5_dataset[category][sequence]["POINT_3D"][image_idx].reshape(9, 3)
        else:
            raise ValueError(f"Mode not supported: {self.mode}")

    def get_image(self, idx, train=False):
        df = self._get_df(train)
        if self.mode == "hdf5":
            category, sequence, image_id = self._hdf5_parse_uid(idx, train)
            hdf5_dataset = self._pick_hdf5_dataset(train)
            image_idx = list(hdf5_dataset[category][sequence]["IMAGE_ID"]).index(
                image_id
            )
            jpeg_data = hdf5_dataset[category][sequence]["IMAGE"][image_idx]
            # image = Image.frombytes('RGBA', (128,128), jpeg_data, 'raw')
            image = Image.open(io.BytesIO(jpeg_data))
            # img= cv2.imdecode(self.hdf5_dataset[category][sequence]["IMAGE"][image_idx],cv2.IMREAD_ANYCOLOR)
            return image
        else:
            raise ValueError("To be implemented!")

    def _get_df(self, train):
        if train:
            df = self.train_info_df
        else:
            df = self.info_df
        return df

    def _hdf5_parse_uid(self, idx, train=False):
        df = self._get_df(train)
        uid = df.iloc[idx]["uid"]
        m = re.match("hdf5_(\w+)/(\d+)_(\d+)", uid)
        category, sequence, image_id = m[1], m[2], int(m[3])
        return category, sequence, image_id

    def _raw_get_points(self, idx: int, train=False):
        """Get 2d and 3d points for a specific frame.

        Args:
            df (pd.DataFrame): Embeddings meta data frame.
            idx (int): Index of the frame in the dataframe.

        Returns:
            tuple: 2d points, 3d points relative to camera.
        """
        if train:
            df = self.train_info_df
        else:
            df = self.info_df

        idx = fix_idx(idx)
        sequence_annotations = self._raw_get_sequence_annotations(
            df.iloc[idx]["category"],
            df.iloc[idx]["batch_number"],
            df.iloc[idx]["sequence_number"],
        )
        frame = int(df.iloc[idx]["frame"])
        object_id = int(df.iloc[idx]["object_id"])
        keypoints = (
            sequence_annotations.frame_annotations[frame]
            .annotations[object_id]
            .keypoints
        )
        points_2d = []
        points_3d = []
        for keypoint in keypoints:
            point_2d = (
                keypoint.point_2d.x,
                keypoint.point_2d.y,
                keypoint.point_2d.depth,
            )
            point_3d = (keypoint.point_3d.x, keypoint.point_3d.y, keypoint.point_3d.z)
            points_2d.append(point_2d)
            points_3d.append(point_3d)
        return np.array(points_2d), np.array(points_3d)

    def _raw_get_sequence_annotations(
        self,
        category: str,
        batch_number: str,
        sequence_number: str,
        annotations_path="/home/raphael/datasets/objectron/annotations",
    ):
        """Get annotation data for a video sequence.

        Args:
            category (str): Category in the objectron dataset.
            batch_number (str): Batch number.
            sequence_number (str): Sequence number.
            annotations_path (str, optional): Location of the Objectron annotation files. Defaults to "/home/raphael/datasets/objectron/annotations".

        Returns:
            annotations: Google's annotations in their format.
        """
        sequence = annotation_protocol.Sequence()
        annotation_file = (
            f"{annotations_path}/{category}/{batch_number}/{sequence_number}.pbdata"
        )
        with open(annotation_file, "rb") as pb:
            sequence.ParseFromString(pb.read())
        return sequence

    def get_plane(self, idx: int, train=False):
        if self.mode == "raw":
            return self._raw_get_plane(idx, train)
        elif self.mode == "hdf5":
            category, sequence, image_id = self._hdf5_parse_uid(idx, train)
            hdf5_dataset = self._pick_hdf5_dataset(train)
            image_idx = list(hdf5_dataset[category][sequence]["IMAGE_ID"]).index(
                image_id
            )
            return (
                hdf5_dataset[category][sequence]["PLANE_CENTER"][image_idx],
                hdf5_dataset[category][sequence]["PLANE_NORMAL"][image_idx],
            )
        else:
            raise ValueError(f"Mode not supported: {self.mode}")

    def _raw_get_plane(self, idx: int, train=False):
        """Get object plane for a specific camera frame.

        Args:
            df (pd.DataFrame): Embeddings meta data frame.
            idx (int): Index of the frame in the dataframe.

        Returns:
            tuple: 2d points, 3d points relative to camera.
        """
        if train:
            df = self.train_info_df
        else:
            df = self.info_df
        idx = int(idx)
        sequence_annotations = self._raw_get_sequence_annotations(
            df.iloc[idx]["category"],
            df.iloc[idx]["batch_number"],
            df.iloc[idx]["sequence_number"],
        )
        frame = int(df.iloc[idx]["frame"])

        plane_center = sequence_annotations.frame_annotations[frame].plane_center
        plane_normal = sequence_annotations.frame_annotations[frame].plane_normal

        return np.array(plane_center), np.array(plane_normal)

    def _raw_get_camera(self, idx: int, train=False):
        """Get camera information for a specific trame.

        Args:
            df (pd.DataFrame): Embeddings meta data frame.
            idx (int): Index of the frame in the dataframe.

        Returns:
            object: Google's camera information for the frame.
        """
        if train:
            df = self.train_info_df
        else:
            df = self.info_df
        idx = fix_idx(idx)
        sequence_annotations = self._raw_get_sequence_annotations(
            df.iloc[idx]["category"],
            df.iloc[idx]["batch_number"],
            df.iloc[idx]["sequence_number"],
        )
        frame = int(df.iloc[idx]["frame"])
        frame_annotation = sequence_annotations.frame_annotations[frame]
        return frame_annotation.camera

    def _raw_get_intrinsics(self, idx, train=False):
        camera = self._raw_get_camera(idx, train)
        return np.array(camera.intrinsics).reshape(3, 3)

    def get_intrinsics(self, idx, train=False):
        if self.mode == "raw":
            return self._raw_get_intrinsics(idx, train)
        elif self.mode == "hdf5":
            category, sequence, image_id = self._hdf5_parse_uid(idx, train)
            hdf5_dataset = self._pick_hdf5_dataset(train)
            image_idx = list(hdf5_dataset[category][sequence]["IMAGE_ID"]).index(
                image_id
            )
            return hdf5_dataset[category][sequence]["INTRINSIC_MATRIX"][
                image_idx
            ].reshape(3, 3)
        else:
            raise ValueError(f"Mode not supported: {self.mode}")

    @staticmethod
    def _get_subset(info_df, embeddings, ratio):
        if ratio == 1:
            return info_df, embeddings
        # info_df["video_uid"]=info_df["category"]+"_"+info_df["video_id"]
        video_uids = list(info_df["sequence_uid"].unique())
        videos_uids_subset = random.sample(video_uids, int(len(video_uids) * ratio))
        print(
            f"Using a subset of {len(videos_uids_subset)} out of {len(video_uids)} total sequences for evaluation."
        )

        info_df_subset = info_df[info_df["sequence_uid"].isin(videos_uids_subset)]
        embeddings_subset = embeddings[:, list(info_df_subset.index)]
        info_df_subset = info_df_subset.reset_index()
        return info_df_subset, embeddings_subset

    def set_trainsubset(self, ratio):
        train_info_df, train_embeddings = self._get_subset(
            self.train_info_df, self.train_embeddings, ratio
        )
        self.train_info_df = train_info_df
        self.train_embeddings = train_embeddings

    def get_category(self, idx, train=False):
        df = self._get_df(train)
        if self.mode == "raw":
            return df.iloc[idx]["category"]
        elif self.mode == "hdf5":
            category, _, _ = self._hdf5_parse_uid(idx, train)
            return category
        else:
            raise ValueError(f"Mode not supported: {self.mode}")

    def get_sequence_uid(self, idx, train=False):
        df = self._get_df(train)
        return df.iloc[idx]["sequence_uid"]

    def parse_info_df(self, info_df, subset="valid"):
        """Parses an embedding meta-data dataframe. (The output of SimSiam)

        Args:
            info_df (pd.DataFrame): Pandas Dataframe, as output by the "read experiment" function.
            subset (str, optional): Which subset to use. Can be "train", "valid" or test. Defaults to "valid".
        """
        info_df["category"] = info_df["uid"].str.extract("(.*?)-")
        info_df["sequence_uid"] = info_df["uid"].str.extract("(batch\-\d+_\d+_\d+)")
        info_df["frame"] = info_df["uid"].str.extract("-(\d+)$")
        info_df["video_id"] = info_df["uid"].str.extract("(batch\-\d+_\d+)")
        info_df["object_id"] = info_df["uid"].str.extract("batch\-\d+_\d+_(\d+)")
        info_df["batch_number"] = info_df["uid"].str.extract("(batch\-\d+)")
        info_df["sequence_number"] = info_df["uid"].str.extract("batch\-\d+_(\d+)_\d+")
        info_df["filepath"] = (
            f"/home/raphael/datasets/objectron/96x96/{subset}/"
            + info_df["category"]
            + "/"
            + info_df["sequence_uid"]
            + "."
            + info_df["frame"]
            + ".jpg"
        )
        info_df["filepath_full"] = (
            "/home/raphael/datasets/objectron/640x480_full/"
            + info_df["category"]
            + "/"
            + info_df["sequence_uid"]
            + "."
            + info_df["frame"]
            + ".jpg"
        )
        if self.mode == "hdf5":
            info_df["sequence_uid"] = info_df["uid"].str.extract("hdf5_(\w+/\d+)_")

def main():
    global args, experiment, ground_plane, symmetric, rescale, all_match_idxs, use_cupy
    """Command line tool for evaluating zero shot pose estimation
    on objectron."""
    parser = argparse.ArgumentParser(
        description="Command line tool for evaluating zero shot pose estimation on objectron."
    )
    parser.add_argument(
        "experiment",
        type=str,
        help="Experiment folder location. i.e. ../SimSiam/outputs/objectron_96x96_experiment_synchflip_next",
    )
    parser.add_argument(
        "--subset_size",
        type=int,
        default=1000,
        help="Number of samples for 3D IoU evaluation",
    )
    parser.add_argument(
        "--ground_plane", default=True, help="If enabled, snap to ground plane"
    )
    parser.add_argument(
        "--iou_t",
        default=0.5,
        help="IoU threshold required to consider a positive match",
    )
    parser.add_argument(
        "--symmetric",
        action="store_true",
        help="Rotate symetric objects (cups, bottles) and keep maximum IoU.",
    )
    parser.add_argument(
        "--rescale", action="store_true", help="Rescale 3d bounding box"
    )
    parser.add_argument(
        "--random_bbox",
        action="store_true",
        help="Fit a randomly selected bbox instead of the nearest neighbor",
    )
    parser.add_argument(
        "--random_bbox_same",
        action="store_true",
        help="Fit a randomly selected bbox from same category instead of the nearest neighbor",
    )
    parser.add_argument(
        "--trainset-ratio",
        type=float,
        default=1,
        help="Ratio of the training set sequences used for inference",
    )
    parser.add_argument(
        "--single_thread", action="store_true", help="Disable multithreading."
    )
    parser.add_argument("--cpu", action="store_true", help="Disable cuda accelaration.")
    parser.add_argument(
        "--no_align_axis",
        action="store_true",
        help="Don't to to align axis with ground plane.",
    )
    parser.add_argument(
        "--legacy", action="store_true", help="Deprecated legacy evalution mode"
    )
    parser.add_argument(
        "--test", action="store_true", help="Evaluate on test set embeddings"
    )
    args = parser.parse_args()
    symmetric = args.symmetric
    rescale = args.rescale

    if args.cpu:
        use_cupy = False

    experiment = ExperimentHandlerFile(args.experiment, args.test)

    if args.trainset_ratio > 0 and args.trainset_ratio <= 1:
        experiment.set_trainsubset(args.trainset_ratio)
    else:
        raise ValueError("Training set ratio must be between 0 and 1!")

    all_match_idxs = find_all_match_idx(
        experiment.embeddings, experiment.train_embeddings, 0
    )
    # get_iou_mp(1)
    if args.subset_size < len(experiment.info_df):
        subset = random.sample(range(0, len(experiment.info_df)), args.subset_size)
    else:
        print(
            f"Evaluating on all samples size subset size ({args.subset_size}) is larger that test set size ({len(experiment.info_df)})."
        )
        subset = list(range(0, len(experiment.info_df)))
        random.shuffle(subset)

    ious = {}
    results = []
    ious_aligned = []
    threshold = args.iou_t
    valid_count = 0
    get_iou_params = []

    for idx in subset:
        # params = (idx, args.symmetric, args.rescale)
        get_iou_params.append(idx)
    if not args.single_thread:
        with get_context("fork").Pool(4) as p:
            results = list(tqdm(p.imap(get_iou_mp, get_iou_params), total=len(subset)))
    else:
        for idx in tqdm(get_iou_params):
            results.append(get_iou_mp(idx))

    for iou, idx, match_idx in results:
        category = experiment.get_category(idx, train=False)
        if not category in ious:
            ious[category] = []
        if iou > threshold:
            valid_count += 1
        ious[category].append(float(iou))

    ious = pd.DataFrame.from_dict(ious, orient="index").T
    ious.to_csv("raw_results.txt")
    print(f"{'category' : <10}\tmean iou\tmedian iou\tAP at iou_t")
    for category in sorted(ious.columns):
        column = ious[category]
        ap_at_iout = (column > args.iou_t).sum() / column.notnull().sum()
        print(
            f"{category: <10}\t{column.mean():0.2f}\t\t{column.median():0.2f}\t\t{ap_at_iout:0.2f}"
        )

if __name__ == "__main__":
    main()


import DES_8_Round as c
import sys

p =  [14,17,11,24,1,5,3,28,15,6,21,10,23,19,12,4,26,8,16,7,27,20,13,2,41,52,31,37,47,55,30,40,51,45,33,48,44,49,39,56,34,53,46,42,50,36,29,32]
rotate= [1,1,2,2]
rotate_rev=[2,2,1,1]
from_64_to_56=[57,49,41,33,25,17,9,1,58,50,42,34,26,18,10,2,59,51,43,35,27,19,11,3,60,52,44,36,63,55,47,39,31,23,15,7,62,54,46,38,30,22,14,6,61,53,45,37,29,21,13,5,28,20,12,4]
def add_zero(x,num):
    h=len(x)
    if h<num:
        for i in range(num-h):
            x="0"+x
    return x

def right_shift(string,d):
    Lfirst = string[0 : d]
    Lsecond = string[d :]
    Rfirst = string[0 : len(string)-d]
    Rsecond = string[len(string)-d : ]
    return Rsecond+Rfirst

def left_shift(string,d):
    Lfirst = string[0 : d]
    Lsecond = string[d :]
    Rfirst = string[0 : len(string)-d]
    Rsecond = string[len(string)-d : ]
    return Lsecond+Lfirst

def from_48_to_56(key):
	key_list=['x']*56
	i=0
	key=list(key)
	for x in p:
		key_list[x-1]=key[i]
		i=i+1
	string=''.join(key_list)
	return string

def blocks(key):
	block=['b']*9
	block[8]=key
	block[7]=right_shift(block[8][:28],2)+right_shift(block[8][28:],2)
	block[6]=right_shift(block[7][:28],2)+right_shift(block[7][28:],2)
	block[5]=right_shift(block[6][:28],2)+right_shift(block[6][28:],2)
	block[4]=right_shift(block[5][:28],2)+right_shift(block[5][28:],2)
	block[3]=right_shift(block[4][:28],2)+right_shift(block[4][28:],2)
	block[2]=right_shift(block[3][:28],2)+right_shift(block[3][28:],2)
	block[1]=right_shift(block[2][:28],1)+right_shift(block[2][28:],1)
	block[0]=right_shift(block[1][:28],1)+right_shift(block[1][28:],1)
	return block[0]

def brute_force(keyfinal):
	for x in range(2**14):
		digits=add_zero(bin(x)[2:],14)
		digits=list(digits)
		counter=0
		key=list(keyfinal)
		for i in range(56):
			if key[i] == 'x':
				key[i] = digits[counter]
				counter=counter+1
		key_56=''.join(key)
		key_64=['0']*64
		i=0
		for u in from_64_to_56:
			key_64[u-1]=key[i]
			i=i+1

		key_64=''.join(key_64)
		key_64=add_zero(hex(int(key_64,2))[2:],16)
		strng='133457799BBCDFF2'
		cipher=c.enc(strng)
		if c.enc2(strng,key_64) == cipher:
			return key_56
			break
	return key_56

def answer(give_key):
	return brute_force(blocks(from_48_to_56(give_key)))


from bs4 import BeautifulSoup as BS
import requests
import lxml
import os

Header = {'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36'}
file_path = ''
img_prefix = 'https://i.nhentai.net/galleries/'

def Init() :
	global code
	hentai_id = input('Enter id : ')
	url = f'https://nhentai.net/g/{hentai_id}/'
	web = requests.get(url, headers=Header)
	code = BS(web.content,'lxml')

def get_info() :
	global name
	title = code.find('h2')
	name = title.get_text()
	print(f'Hentai name : {name}')

def Download() :
	# create folder
	folder = file_path+name+'\\'
	try :
		os.mkdir(folder)
	except :
		pass

	pages = code.find_all('div', class_='thumb-container')
	print(f'Hentai pages : {len(pages)}')
	# get image url
	link = pages[0].a.find('img')
	id = link['data-src'].split('/')[-2]
	img_url = img_prefix+id+'/'
	# download
	for cnt in range(1,len(pages)+1) :
		print(f'Downloading ... {img_url}{cnt}.jpg')
		open(f'{folder}{cnt}.jpg','wb').write(requests.get(f'{img_url}{cnt}.jpg', headers=Header).content)

Init()
get_info()
Download()
print('Finish !')


import echo_util as util
import reverb_hp_subroutines as reverb
import warnings
import os
import numpy as np
import matplotlib.pyplot as plt
import healpy as hp
from astropy import constants as const
from astropy.coordinates import SkyCoord
from healpy.newvisufunc import projview, newprojplot
from tqdm import tqdm
plt.rcParams["figure.dpi"] = 300
print("Healpy version {}".format(hp.__version__))
util.set_mod_defaults()
util.set_times()
warnings.filterwarnings('ignore')

data_dir = os.path.abspath(os.path.join(
    os.path.dirname(__file__), '..', 'Data'))
figure_dir = os.path.abspath(os.path.join(
    os.path.dirname(__file__), '..', 'Figures'))
frame_dir = os.path.abspath(os.path.join(
    os.path.dirname(__file__), '..', 'Movies/Frames'))

def make_figs_9_10(root, ntimes=[34], folder=".", savefolder="."):

    print("Making composition figures for {}...".format(root))
    for ntime in tqdm(ntimes):
        #print("ntime:", ntime)
        directory = "{}/{}".format(folder, root)
        hpx_map, hpx_mapA, groups, lnA_bins, summed = reverb.get_maps_from_data2(
            ntime, nside=64, smooth=20, directory=directory, use_lnA_bins=True, summed=True)
        hpx_mapA_masked = hp.ma(np.log(hpx_mapA))

        yr = 365.25 * 24.0 * 3600.0
        delta_t = 0.03 * 1e6 * const.pc.cgs.value / const.c.cgs.value / yr / 1e6
        dt_plot = delta_t * util.dt_plot_sim

        #hpx_mapA_masked.mask = (hpx_map < 1e-2)
        to_plot = groups["7"]+groups["8"]
        to_plot = groups["0"]
        #print (groups.keys())
        override_plot_properties = {
            "figure_width": 9, "figure_size_ratio": 5./9.},
        fontsize_dict = {"xtick_label": 18,
                         "ytick_label": 18, "title": 18, "cbar_label": 18}

        all_groups = np.zeros_like(groups["0"])
        for i in groups.keys():
            all_groups += groups[i]

        to_plots = [groups["7"]+groups["8"], groups["2"]]

        #print (np.sum(summed), np.sum(hpx_map))

        cmaps = ["Oranges", "Purples"]
        labels = ["\ln A > 3.5", "1 < \ln A < 1.5"]
        savename = ["heavymap_{}_{}".format(root, ntime),
                    "lightmap_{}_{}".format(root, ntime)]

        fig = plt.figure()
        for i, to_plot in enumerate(to_plots):

            # plt.subplot(4,2,i+1)
            if np.max(to_plot) < 5e-7:
                vmin = 5e-7
                vmax = 1
            else:
                vmin = 0
                vmax = None

            projview(to_plot * util.skymap_renorm,
                     unit="UHECR Flux",
                     cb_orientation="vertical",
                     graticule=True,
                     projection_type="hammer",
                     graticule_labels=True,
                     xtick_label_color="k",
                     title=r"$t={:.1f}~{{\rm Myr}},~{}$".format(
                         ntime * dt_plot + 0.05, labels[i]),
                     cmap=cmaps[i], min=vmin, max=vmax,
                     override_plot_properties=override_plot_properties,
                     fontsize=fontsize_dict)

            plt.savefig("{}/{}.png".format(savefolder,
                        savename[i]), dpi=300, transparent=True)
            # plt.savefig("reverb_maps/{}.pdf".format(savename[i]), format="pdf")
            # plt.close("all")

def parse_args():
    import argparse
    parser = argparse.ArgumentParser(
        prog='Healpy_Figures',
        description='make Healpy figures for Taylor et al. UHECR echoes')

    parser.add_argument('-m', '--movies', action='store_true',
                        default=False, help="Make movie frames")

    parser.add_argument('--no-figures', action='store_true', default=False,
                        help="Don't make figures")

    parser.add_argument('-f', '--files', nargs='+', type=str,
                        help="which files to make figures from",
                        default=["ModelA", "ModelB", "ModelC"])

    args = parser.parse_args()
    return args

def run_paper_figures(roots=["ModelA", "ModelB", "ModelC"]):
    times = util.plot_times

    yr = 365.25 * 24.0 * 3600.0
    delta_t = 0.03 * 1e6 * const.pc.cgs.value / const.c.cgs.value / yr / 1e6
    dt_plot = delta_t * util.dt_plot_sim
    maxes = [None for t in times]

    for iroot, root in enumerate(tqdm(roots)):

        make_figs_9_10(root, ntimes=[times[-1]], folder=data_dir,
                       savefolder=figure_dir)

        print ("Making skymap figures for {}...".format(root))
        reverb.make_skymap_plots(root, times, dt_plot, smooths=20,
                                 maxes=maxes, skip_header=1, folder=data_dir,
                                 savefolder=figure_dir, renorm = util.skymap_renorm)

def run_movie_frames(roots=["ModelA", "ModelB", "ModelC"]):
    times = np.arange(0, util.ndt_max, 1)

    yr = 365.25 * 24.0 * 3600.0
    delta_t = 0.03 * 1e6 * const.pc.cgs.value / const.c.cgs.value / yr / 1e6
    dt_plot = delta_t * util.dt_plot_sim
    maxes = [None for t in times]

    for iroot, root in enumerate(roots):

        make_figs_9_10(root, ntimes=times, folder=data_dir,
                       savefolder=frame_dir)

        reverb.make_skymap_plots(root, times, dt_plot, smooths=20,
                                 maxes=maxes, skip_header=1, folder=data_dir,
                                 savefolder=frame_dir, renorm = util.skymap_renorm)

if __name__ == "__main__":
    # parse arguments
    args = parse_args()

    # make movies and figures as required
    if args.no_figures == False:
        run_paper_figures(roots=args.files)
    if args.movies:
        run_movie_frames(roots=args.files)


import math
import random

import pygame as pg

BLACK = (0, 0, 0)
GRAY = (224, 224, 224)
WHITE = (255, 255, 255)
GREEN = (23, 232, 215)
GREEN1 = (172, 255, 112)
# Initialize the pygame
pg.init()

# parameter
NumberOfTracks = 5
weight = 400
high = 750
slowSpeed = 0.01
fastSpeed = 10
space = 1
track = weight / NumberOfTracks
index = 0
boxSpeed = slowSpeed
backgroundTopMargin = 50
boxMoving = backgroundTopMargin - 10

# Box rect size
sizeBox = track - 4 * space

# Box
boxScore = []
boxX = []
boxY = []
positionY = []
# # how many tracks
# for i in range(NumberOfTracks):
#     boxScore.append([])
#     boxX.append([])
#     boxY.append([])
#     positionY.append(high - sizeBox)

# Create the screen
screen = pg.display.set_mode((weight, high))

# Background
background = pg.image.load('image/background.jpg')
background = pg.transform.scale(background, (weight, high))

# font
font_32 = pg.font.Font('freesansbold.ttf', 32)
font_16 = pg.font.Font('freesansbold.ttf', 16)
text_size_x = 9.5
text_size_y = 16
# get score
total_score = 0

# computing length of text
def compute_length_of_text(text):
    return len(str(text)) * text_size_x

# restart game
def restart_game():
    global boxScore, boxY, boxX, positionY, total_score
    boxScore = []
    boxX = []
    boxY = []
    positionY = []
    total_score = 0
    # how many tracks
    for k in range(NumberOfTracks):
        boxScore.append([])
        boxX.append([])
        boxY.append([])
        positionY.append(high - sizeBox)

# get score
def get_score():
    score_str = font_32.render(str(total_score), True, WHITE)
    screen.blit(score_str, (weight / 2 - compute_length_of_text(total_score), text_size_y))

# background
def set_background():
    screen.blit(background, (0, 0))
    for i in range(NumberOfTracks - 1):
        pg.draw.rect(screen, GRAY, pg.Rect((i + 1) * (track - space), backgroundTopMargin, 2 * space, high))
    pg.draw.rect(screen, BLACK, pg.Rect(0, backgroundTopMargin, weight, 5 * space))

# Create Box
def create_box(score, x, y, size_box):
    global text_size_x, text_size_y
    pg.draw.rect(screen, color(score), pg.Rect(x, round(y), size_box, size_box))
    score_str = font_32.render(str(score), True, WHITE)
    screen.blit(score_str, (x + size_box / 2 - compute_length_of_text(score), y + size_box / 2 - text_size_y))
    # pg.display.flip()

# Computer color by score
def color(score):
    green = 229 - score * 2 if 229 - score * 2 > 128 else 128
    blue = 204 - score * 2 if 204 - score * 2 > 0 else 0
    red = 255 - score * 2 if 204 - score * 2 > 0 else 0
    return red, green, blue

# check box collision
# score 分數
# y 座標
# x 座標
# tracks_index 第幾軌道
# item_index 上一個item位置
def is_collision(score, box_y, box_x, tracks_index, item_index):
    global total_score
    if item_index < 0:
        return len(score[tracks_index])
    is_mix = False  # 是否有合併
    high_box = len(score[tracks_index]) - 1
    if high_box < 0:
        return len(score[tracks_index])
    temp_get_score = 0  # 得分
    target = score[tracks_index][high_box]  # 目標分數
    save_index = item_index  # 最後儲存的座標
    # 合併規則
    # EX 2(L)2(T)
    if tracks_index - 1 >= 0 and high_box < len(score[tracks_index - 1]) and target == score[tracks_index - 1][
        high_box]:
        score[tracks_index][high_box] *= 2
        temp_get_score = score[tracks_index][high_box]
        del_box(score, box_x, box_y, tracks_index - 1, high_box)  # delete box
        is_mix = True
    # EX 2(T)2(R)
    if tracks_index + 1 < len(score) and high_box < len(score[tracks_index + 1]) and target == score[tracks_index + 1][
        high_box]:
        score[tracks_index][high_box] *= 2
        temp_get_score = score[tracks_index][high_box]
        del_box(score, box_x, box_y, tracks_index + 1, high_box)  # delete box
        is_mix = True
    # EX:   2(T)
    #       2
    if high_box > 0 and target == score[tracks_index][high_box - 1]:
        score[tracks_index][high_box] *= 2
        score[tracks_index][high_box - 1] = score[tracks_index][high_box]
        del_box(score, box_x, box_y, tracks_index, high_box)  # delete box
        is_mix = True
        save_index -= 1
        temp_get_score = score[tracks_index][high_box - 1]

    total_score += temp_get_score  # 得分
    if not is_mix:
        return len(score[tracks_index])

    return is_collision(score, box_y, box_x, tracks_index, save_index)

# delete box
def del_box(score, box_x, box_y, x, y):
    del score[x][y]
    del box_x[x][y]
    del box_y[x][len(box_y[x]) - 1]

# game over
def is_game_over(box_y):
    global total_score
    if len(box_y) - 1 >= 0 and box_y[len(box_y) - 1] <= sizeBox:
        top_score_text = "Top Score"
        restart_text = "RESTART"
        game_over = font_16.render(top_score_text, True, WHITE)
        restart = font_32.render(restart_text, True, WHITE)
        total = font_32.render(str(total_score), True, WHITE)
        pg.draw.rect(screen, GREEN, pg.Rect(weight / 4, high / 3, weight / 2, high / 4))
        screen.blit(game_over, (weight / 2 - len(str(top_score_text)) * 4.5, high / 2 - 7 * text_size_y))
        screen.blit(total, (weight / 2 - compute_length_of_text(total_score), high / 2 - 5.5 * text_size_y))
        screen.blit(restart, (weight / 2 - compute_length_of_text(restart_text) - 7, high / 2 - 2 * text_size_y))
        return True
    return False

# Game Loop
# restart game
restart_game()
running = True
game_pass = True
initial_score = [int(math.pow(2, random.randint(1, 5))), int(math.pow(2, random.randint(1, 5)))]
while running:
    screen.fill(BLACK)
    set_background()
    # get score
    get_score()
    # Listen event
    for event in pg.event.get():
        # Close screen
        if event.type == pg.QUIT:
            running = False
        # Right Click
        if event.type == pg.MOUSEBUTTONDOWN:
            if game_pass:
                index = int(pg.mouse.get_pos()[0] / track)
                boxSpeed = fastSpeed
            elif 120 < pg.mouse.get_pos()[0] in range(120, 290) and pg.mouse.get_pos()[1] in range(340, 370):
                game_pass = True
                restart_game()

    # Show all of box
    for i in range(len(boxScore)):
        for j in range(len(boxScore[i])):
            create_box(boxScore[i][j], boxX[i][j], boxY[i][j], sizeBox)

    # Show next box
    create_box(initial_score[1], weight / 5, 10, sizeBox / 2)

    # check game over
    if is_game_over(boxY[index]):
        game_pass = False
        pg.display.update()
        continue

    # initial Box moving
    boxMoving += boxSpeed
    positionX = 2 * space + index * track
    create_box(initial_score[0], positionX, boxMoving, sizeBox)

    # initial box and save box
    if positionY[index] < boxMoving:
        # save box
        boxScore[index].append(initial_score[0])
        boxX[index].append(positionX)
        boxY[index].append(positionY[index])
        # initial box
        boxMoving = 50
        boxSpeed = slowSpeed
        initial_score[0]=initial_score[1]
        initial_score[1] = int(math.pow(2, random.randint(1, 5)))

    # check box collision
    number = is_collision(boxScore, boxY, boxX, index, len(boxScore) - 1)
    # 計算boxY軸最高線 軌道高-(目前軌道item數量+1)*box高 - box和box之間的距離
    positionY[index] = high - (number + 1) * sizeBox - 2 * number * space

    # update draw
    # pg.display.flip()
    # update screen
    pg.display.update()


from .piece import *

class King(Piece):
    names = ["K", "k"]

    def moves_from_position(self, board, position):
        moves = []
        for x in range(-1, 2):
            for y in range(-1, 2):
                new_x_pos = position[0] + x
                new_y_pos = position[1] + y
                if self._valid_target(board, [new_x_pos, new_y_pos]):
                    moves.append([new_x_pos, new_y_pos])
        return moves


#!/usr/bin/env python3 -u
# -*- mode: python; py-indent-offset: 4; py-continuation-offset: 4 -*-
#
# Change shebang line to '/usr/bin/python -3' for python 3.x porting warnings
"""
This script drives a PR testing build.  It assume that Trilinos is already
cloned under $WORKSPACE/Trilinos and that the 'origin' remote points to
$TRILINOS_TARGET_REPO (but that is not checked here).

As long as the ${WORKSPACE}/Trilinos git repo has the correct 'origin', this
script will automatically set it up to do the merge correctly, no matter
what its state before this script is called (i.e. from a past PR
attempt). Unless the Trilinos/.git directory becomes corrupted, there should
*NEVER* be any need to delete and reclone this Trilinos git repo.

This script can be run in a mode where the driver scripts are run from one
Trilinos git repo and operate on another Trilinos git repo that gets
manipulated in order to merge the "source" topic branch into the "target"
branch.  This makes it easy to test changes to the PR scripts.  But if this
script is run from ${WORKSPACE}/Trilinos, then these repos are one and the same
and we get the correct behavior for PR testing.

Expectations
------------

### Required Environment Variables
- MODULESHOME : Path to the location where modulefiles are.
- CC : C Compiler
- FC : Fortran Compiler
- PULLREQUEST_CDASH_TRACK : Which CDash track should this result be published to?

### Other Expectations?

"""
from __future__ import print_function

# turn off generation of the .pyc/.pyo files.
import sys
sys.dont_write_bytecode = True

import argparse
import os
import sys

import trilinosprhelpers

def parse_args():
    """
    This function parses the command line arguments for the script.

    Returns:
        Namespace object containing the arguments from the command line.
    """
    parser    = argparse.ArgumentParser(description='Parse the repo and build information')
    required  = parser.add_argument_group('Required Arguments')
    optional  = parser.add_argument_group('Optional Arguments')
    cwd       = os.getcwd()

    default_workspace = cwd
    if "WORKSPACE" in os.environ.keys():
        default_workspace = os.environ["WORKSPACE"]

    # Set up path to the packageenables aand subprojects files.
    default_filename_packageenables = os.path.join("..", "packageEnables.cmake")
    default_filename_subprojects = os.path.join("..", "package_subproject_list.cmake")

    required.add_argument('--source-repo-url',
                          dest="source_repo_url",
                          action='store',
                          help='Repo with the new changes',
                          required=True)

    required.add_argument('--target-repo-url',
                          dest="target_repo_url",
                          action='store',
                          help='Repo to merge into',
                          required=True)

    required.add_argument('--target-branch-name',
                          dest="target_branch_name",
                          action='store',
                          help='Branch to merge into',
                          required=True)

    required.add_argument('--pullrequest-build-name',
                          dest="pullrequest_build_name",
                          action='store',
                          help='The Jenkins job base name',
                          required=True)

    required.add_argument('--genconfig-build-name',
                          dest="genconfig_build_name",
                          action='store',
                          help='The job base name for the cmake configuration',
                          required=True)

    required.add_argument('--pullrequest-number',
                          dest="pullrequest_number",
                          action='store',
                          help='The github PR number',
                          required=True)

    required.add_argument('--jenkins-job-number',
                          dest="jenkins_job_number",
                          action='store',
                          help='The Jenkins build number',
                          required=True)

    optional.add_argument('--source-dir',
                          dest="source_dir",
                          action='store',
                          default="UNKNOWN",
                          help="Directory containing the source code to compile/test.",
                          required=False)

    optional.add_argument('--build-dir',
                          dest="build_dir",
                          action='store',
                          default="UNKNOWN",
                          help="Path to the build directory.",
                          required=False)

    optional.add_argument('--use-explicit-cachefile',
                          dest='use_explicit_cachefile',
                          action='store_true',
                          default=False,
                          help="Use -DTrilinos_CONFIGURE_OPTIONS_FILE instead of -C.",
                          required=False)

    optional.add_argument('--ctest-driver',
                          dest="ctest_driver",
                          action='store',
                          default="UNKNOWN",
                          help="Location of the CTest driver script to load via `-S`.",
                          required=False)

    optional.add_argument('--ctest-drop-site',
                          dest="ctest_drop_site",
                          action='store',
                          default="testing.sandia.gov",
                          help="URL of the cdash server to post to.",
                          required=False)

    optional.add_argument('--pullrequest-cdash-track',
                          dest='pullrequest_cdash_track',
                          action='store',
                          default="Pull Request",
                          help="The CDash Track to add results to. Default=%(default)s",
                          required=False)

    optional.add_argument('--pullrequest-env-config-file',
                          dest='pullrequest_env_config_file',
                          action='store',
                          default=os.path.join(cwd, "pr_config/pullrequest.ini"),
                          help="The Trilinos PR driver configuration file " + \
                               "containing job mappings to environment specifications. Default=%(default)s",
                          required=False)

    optional.add_argument('--pullrequest-gen-config-file',
                          dest='pullrequest_gen_config_file',
                          action='store',
                          default=os.path.join(cwd, "../GenConfig/src/gen-config.ini"),
                          help="The Trilinos PR driver configuration file " + \
                               "containing job mappings to cmake specifications. Default=%(default)s",
                          required=False)

    optional.add_argument('--workspace-dir',
                          dest="workspace_dir",
                          action='store',
                          default=default_workspace,
                          help="The local workspace directory that Jenkins set up." +
                               " Default={}".format(default_workspace),
                          required=False)

    desc_package_enables = "The packageEnables.cmake is usually generated by TriBiTS infrastructure " + \
                           "based on which packages contain the changes between the source and target " + \
                           "branches."

    optional.add_argument('--filename-packageenables',
                          dest="filename_packageenables",
                          action="store",
                          default=default_filename_packageenables,
                          help="{} Default={}".format(desc_package_enables, default_filename_packageenables))

    desc_subprojects_file = "The subprojects_file is used by the testing infrastructure. This parameter " + \
                            "allows the default, generated file, to be overridden. Generally this should " + \
                            "not be changed from the defaults."

    optional.add_argument('--filename-subprojects',
                          dest="filename_subprojects",
                          action="store",
                          default=default_filename_subprojects,
                          help="{}. Default={}".format(desc_subprojects_file, default_filename_subprojects))

    optional.add_argument('--test-mode',
                          dest='test_mode',
                          action='store',
                          default='standard',
                          help="PR testing mode. Use 'standard' for normal PR tests, 'installation'" +
                               " for installation testing. Default = %(default)s")

    optional.add_argument('--req-mem-per-core',
                          dest='req_mem_per_core',
                          action='store',
                          default=3.0,
                          help="Minimum required memory per core (GB) to build Trilinos." +
                               "Default = %(default)s")

    optional.add_argument('--max-cores-allowed',
                          dest='max_cores_allowed',
                          action='store',
                          default=12,
                          help="Max cores allowed, if >= 0 we will use the # of " +
                               "detected cores on the system. Default = %(default)s")

    optional.add_argument('--num-concurrent-tests',
                          dest='num_concurrent_tests',
                          action='store',
                          default=-1,
                          help="Set the number of concurrent tests allowd in CTest. " + \
                               "This is equivalent to `ctest -j <num-concurrent-tests>`. "
                               "If > 0 then this value is used, otherwise the value is calculated " + \
                               "based on number_of_available_cores / max_test_parallelism" + \
                               " Default = %(default)s")

    optional.add_argument("--enable-ccache",
                          dest="ccache_enable",
                          action="store_true",
                          default=False,
                          help="Enable ccache object caching to improve build times. Default = %(default)s")

    optional.add_argument("--dry-run",
                          dest="dry_run",
                          action="store_true",
                          default=False,
                          help="Enable dry-run mode. Script will run but not execute the build steps. Default = %(default)s")

    arguments = parser.parse_args()

    # Type conversions
    arguments.max_cores_allowed    = int(arguments.max_cores_allowed)
    arguments.num_concurrent_tests = int(arguments.num_concurrent_tests)
    arguments.req_mem_per_core     = float(arguments.req_mem_per_core)

    # Print the arguments to the console
    print("\n")
    print("+" + "="*78 + "+")
    print("| PullRequestLinuxDriverTest Parameters")
    print("+" + "="*78 + "+")
    print("| - [R] source-repo-url             : {source_repo_url}".format(**vars(arguments)))
    print("| - [R] target_repo_url             : {target_repo_url}".format(**vars(arguments)))
    print("| - [R] target_branch_name          : {target_branch_name}".format(**vars(arguments)))
    print("| - [R] pullrequest-build-name      : {pullrequest_build_name}".format(**vars(arguments)))
    print("| - [R] genconfig-build-name        : {genconfig_build_name}".format(**vars(arguments)))
    print("| - [R] pullrequest-number          : {pullrequest_number}".format(**vars(arguments)))
    print("| - [R] jenkins-job-number          : {jenkins_job_number}".format(**vars(arguments)))
    print("| - [R] source-dir                  : {source_dir}".format(**vars(arguments)))
    print("| - [R] build-dir                   : {build_dir}".format(**vars(arguments)))
    print("| - [R] ctest-driver                : {ctest_driver}".format(**vars(arguments)))
    print("| - [R] ctest-drop-site             : {ctest_drop_site}".format(**vars(arguments)))
    print("|")
    print("| - [O] dry-run                     : {dry_run}".format(**vars(arguments)))
    print("| - [O] enable-ccache               : {ccache_enable}".format(**vars(arguments)))
    print("| - [O] filename-packageenables     : {filename_packageenables}".format(**vars(arguments)))
    print("| - [O] max-cores-allowed           : {max_cores_allowed}".format(**vars(arguments)))
    print("| - [O] num-concurrent-tests        : {num_concurrent_tests}".format(**vars(arguments)))
    print("| - [O] pullrequest-cdash-track     : {pullrequest_cdash_track}".format(**vars(arguments)))
    print("| - [O] pullrequest-env-config-file : {pullrequest_env_config_file}".format(**vars(arguments)))
    print("| - [O] pullrequest-gen-config-file : {pullrequest_gen_config_file}".format(**vars(arguments)))
    print("| - [O] req-mem-per-core            : {req_mem_per_core}".format(**vars(arguments)))
    print("| - [O] test-mode                   : {test_mode}".format(**vars(arguments)))
    print("| - [O] workspace-dir               : {workspace_dir}".format(**vars(arguments)))
    #print("| - [O] : {}".format(**vars(arguments)))
    print("+" + "="*78 + "+")

    return arguments

def main(args):

    pr_config = None

    # Banner
    print("+" + "="*78 + "+")
    print("|")
    print("|   T R I L I N O S   P U L L R E Q U E S T   D R I V E R   S T A R T")
    print("|")
    if args.dry_run:
        print("|                D R Y   R U N   M O D E   E N A B L E D")
        print("|")
    print("+" + "="*78 + "+")
    print("")

    if 'standard' == args.test_mode:
        pr_config = trilinosprhelpers.TrilinosPRConfigurationStandard(args)
    elif 'installation' == args.test_mode:
        pr_config = trilinosprhelpers.TrilinosPRConfigurationInstallation(args)
    else:
        raise KeyError("ERROR: Unknown test mode, {}, was provided.".format(args.test_mode))

    pr_config.prepare_test()

    status = pr_config.execute_test()

    print("PullRequestLinuxDriverTest.py main()> Done.")

    return status

if __name__ == "__main__":
    args = parse_args()
    status = main(args)
    sys.exit(status)