print("starting...")
print("DinoGame by Erik Oellers")
try:
    print("adding packages...")
    import threading
    import time
    import tkinter as tk
    import screeninfo
    import imgbits
    from PIL import Image, ImageTk
    import numpy as np
    import keyboard
    import random
    import traceback
    import sys
    import ctypes
    print("DONE")

    '''
    python.exe -m pip install --upgrade pip
    pip install screeninfo
    pip install keyboard
    pip install pillow
    pip install numpy
    
    '''

    print("Prep shared Variables...")
    class shared:
        def __init__(self):
            self.speed = 1
            self.xpos = 0.1
            self.ypos = 0.755
            self.imgnum = 0
            self.imgspeed = 3
            self.jump = False
            self.jumpheight = 20
            self.jumptime = 0.002
            self.sendobs = 0
            self.obsobjects = []
            self.cactusthreads = []
            self.points = 0
            self.pointstring = "0000"
            self.groundy = 0.755
            self.caccreation = []
            self.cacid = 0
            self.movingcac = []
            self.lost = False
            self.updatecheck = True
            self.endall = False

    s = shared()
    print("Done")

    print("Create Frame")
    width = screeninfo.get_monitors()[0].width
    height = screeninfo.get_monitors()[0].height

    def setdinohight():
        s_height = screeninfo.get_monitors()[0].height
        if s_height == 1080:
            s.ypos = 0.7
            s.groundy = 0.7
        elif s_height == 1440:
            s.ypos= 0.755
            s.groundy = 0.755
        else:
            s.ypos = 0.755
            s.groundy = 0.755
        print("set ground")
    setdinohight()

    #s.ypos = 0.45

    frame_width = round(width / 2.3)
    frame_height = round(height / 3)
    frame = tk.Tk()
    frame.geometry(f"{frame_width}x{frame_height}")
    frame.configure(background="#000000")
    frame.title("DinoGame - Erik Oellers")
    frame.update()

    print("done")
    print("Prep Objects")
    ground = tk.Frame(frame, height=50, width=1200)

    dino = tk.Label(frame, text="", background="#000000")
    dino.place(relx=s.xpos, rely=s.ypos)
    imgcounter = 0

    points = tk.Label(frame, text=s.pointstring, background="#000000", foreground="#ffffff", font=("Helvetica", 25))
    points.place(relx=0.98, rely=0.05, anchor="e")
    print("done")




    print("prep Functions...")
    def controls():
        while True:
            if s.endall:
                raise SystemExit
            if s.lost:
                continue
            if keyboard.is_pressed("space"):
                s.jump = True
                j_time = 0.005
                j_time_multiplier = 1
                for i in range(s.jumpheight * j_time_multiplier):
                    if s.endall:
                        raise SystemExit
                    if s.lost:
                        continue
                    s.ypos -= 0.02
                    time.sleep(j_time * j_time_multiplier / s.speed)
                    print(j_time * j_time_multiplier)
                    j_time += s.jumptime
                    j_time_multiplier += 0.001

                for i in range(s.jumpheight):
                    if s.lost:
                        continue
                    if s.endall:
                        raise SystemExit
                    s.ypos += 0.02
                    time.sleep(j_time * j_time_multiplier / s.speed)
                    print(j_time * j_time_multiplier)
                    j_time -= s.jumptime
                    j_time_multiplier -= 0.01
                s.jump = False
            time.sleep(0.03333334)


    def request_cactus():
        if s.endall:
            raise SystemExit
        size_cac = random.randint(1, 3)
        yadd = 0
        if size_cac == 1:
            yadd = 0.105
        if size_cac == 2:
            yadd = 0.05
        if size_cac == 3:
            yadd = -0.03
        print(size_cac)
                          #Cactus,x,     y,              size   was_send? ID     over?
        caccreation_prev = [None, 1, s.groundy + yadd, size_cac, False, s.cacid, False]
                        #    0    1      2                3       4      5       6
        s.caccreation.append(caccreation_prev)
        localid = s.cacid
        localindex = 0
        s.cacid += 1
        for i in range(len(s.caccreation)):
            if s.caccreation[i][5] == localid:
                localindex = i

        while not s.caccreation[localindex][4]:
            if s.endall:
                raise SystemExit
            time.sleep(0.033333334)
            #print("waiting for send-flag: " + str(s.caccreation[localindex][5]))
        while s.caccreation[localindex][1] > -0.1:
            if s.endall:
                raise SystemExit
            #print("moving to dino: " + str(s.caccreation[localindex][1]))
            s.caccreation[localindex][1] -= 0.01 * s.speed
            time.sleep(0.033334)
        s.caccreation[localindex][2] = 2
        s.caccreation[localindex][6] = True





    def cactusctrl():
        time.sleep(2)
        round = 0
        while True:
            if s.endall:
                raise SystemExit
            if s.sendobs < 1:
                cactus_to_send = 1
            elif s.sendobs < 10:
                cactus_to_send = 2
            elif s.sendobs < 25:
                cactus_to_send = 3
            elif s.sendobs < 50:
                cactus_to_send = 4
            else:
                cactus_to_send = random.randint(5, 10)
            print("sending: " + str(cactus_to_send))

            s.sendobs += cactus_to_send
            for cac in range(cactus_to_send):
                if s.endall:
                    raise SystemExit
                s.cactusthreads.append(threading.Thread(target=request_cactus))
                s.obsobjects.append(cac)
                s.cactusthreads[len(s.cactusthreads) - 1].start()
                print("ThreadCreated")
                time.sleep(random.uniform(1.5, 4.5))


            for thread in s.cactusthreads:
                if s.endall:
                    raise SystemExit
                thread.join()
                threadname = thread.name
                #print("thread joined: " + threadname + " ; " + str(round))
            for cac in s.movingcac:
                try:
                    cac[0].place_forget()
                except:
                    continue
            if s.endall:
                raise SystemExit
            s.movingcac = []
            s.cactusthreads = []
            #print("DONE " + str(round))
            round += 1
            time.sleep(0.03333334)

    def check_exist():
        while True:
            starttime = time.time()
            while not s.updatecheck:
                time.sleep(1)
                endtime = time.time()
                if endtime - starttime > 10:
                    s.endall = True
                    raise SystemExit
            s.updatecheck = False
            time.sleep(1)


    def lost():
        s.lost = True
        #reseting
        s.speed = 1
        s.xpos = 0.1
        s.imgnum = 0
        s.imgspeed = 3
        s.jump = False
        s.jumpheight = 20
        s.jumptime = 0.002
        s.sendobs = 0
        s.obsobjects = []
        s.cactusthreads = []
        s.points = 0
        s.pointstring = "0000"
        s.groundy = 0.755





        #dino img
        dino_img_array = imgbits.dinobits()
        colors = {
            1: (255, 255, 255),
            0: (0, 0, 0)
        }
        picxy = 3
        if True:
            width = len(dino_img_array[2][0]) * picxy
            height = len(dino_img_array[2]) * picxy
            image = Image.new('RGB', (width, height))
            for y, row in enumerate(dino_img_array[2]):
                for x, value in enumerate(row):
                    color = colors[value]
                    for i in range(picxy):
                        for j in range(picxy):
                            image.putpixel((x * picxy + i, y * picxy + j), color)
            return ImageTk.PhotoImage(image)


    print("done")
    print("Starting Threads...")
    control_thread = threading.Thread(target=controls)
    control_thread.start()

    cactus_thread = threading.Thread(target=cactusctrl)
    cactus_thread.start()

    frame_exist_thread = threading.Thread(target=check_exist)
    frame_exist_thread.start()
    print("done")

    print("Starting Mainloop...")
    ground.place(relx=0, rely=0.9)
    count1 = 0
    while True:
        if count1 == 0:
            print("Mainloop Startet!\nClosing Terminal...")
            count1 += 1
            if sys.platform == "win32":
                ctypes.windll.user32.ShowWindow(ctypes.windll.kernel32.GetConsoleWindow(), 0)
        if s.endall:
            raise SystemExit
        if s.speed < 5:
            s.speed += 0.0005
        s.points += 1
        if s.points < 10:
            s.pointstring = "000" + str(s.points)
        elif s.points < 100:
            s.pointstring = "00" + str(s.points)
        elif s.points < 1000:
            s.pointstring = "0" + str(s.points)
        else:
            s.pointstring = str(s.points)
        points.configure(text=s.pointstring)
        if imgcounter < s.imgspeed:
            s.imgnum = 1
        elif imgcounter < s.imgspeed * 2:
            s.imgnum = 0
        else:
            imgcounter = 0
        imgcounter += 1
        dino_img_array = imgbits.dinobits()
        colors = {
            1: (255, 255, 255),
            0: (0, 0, 0)
        }
        picxy = 3
        if not s.jump:
            width = len(dino_img_array[s.imgnum][0]) * picxy
            height = len(dino_img_array[s.imgnum]) * picxy
            image = Image.new('RGB', (width, height))
            for y, row in enumerate(dino_img_array[s.imgnum]):
                for x, value in enumerate(row):
                    color = colors[value]
                    for i in range(picxy):
                        for j in range(picxy):
                            image.putpixel((x * picxy + i, y * picxy + j), color)
            dino_img = ImageTk.PhotoImage(image)
            dino.configure(image=dino_img)
        dino.place_configure(relx=s.xpos, rely=s.ypos)

        cac_moving = False
        for cac in s.movingcac:
            try:
                if cac[1] > 0.5:
                    cac_moving = True
                if cac[1] < 0:
                    cac[0].place_forget()
            except:
                continue
        if True:
            usingcac = None
            for cac in s.caccreation:
                if not cac[4]:
                    cac[4] = True
                    cactusbits = imgbits.cactus()
                    width = len(cactusbits[0]) * cac[3]
                    height = len(cactusbits) * cac[3]
                    image = Image.new('RGB', (width, height))
                    for y, row in enumerate(cactusbits):
                        for x, value in enumerate(row):
                            color = colors[value]
                            for i in range(cac[3]):
                                for j in range(cac[3]):
                                    image.putpixel((x * cac[3] + i, y * cac[3] + j), color)
                    cac_img = ImageTk.PhotoImage(image)
                    cactus = tk.Label(frame, text="", bg="#000000")
                    cactus.place(relx=0.5, rely=0.5)
                    #                   label,   x,     y,        ID,     image
                    s.movingcac.append([cactus, cac[1], cac[2], cac[5], cac_img])
                    #                   0        1      2         3         4
                    #print("CREATED NEW CACT")


        for cact in s.movingcac:
            try:
                cacinfo = s.caccreation[cact[3]]
                cact[0].configure(image=cact[4])
                #print("changed img")
                cact[0].place_configure(relx=cacinfo[1], rely=cacinfo[2])
                if cacinfo[3] == 1:
                    if s.xpos > cacinfo[1] - 0.065 and s.xpos < cacinfo[1]:
                        if s.ypos + 0.155 > cacinfo[2]:
    # -------------------------------------------------------------------------------
                            lostimg = lost()
                            dino.configure(image=lostimg)
                            dino.place_configure(relx=s.xpos, rely=s.ypos)
                            dino.lift()
                            ground.lift()

                            frame.update()

                            for cac in s.movingcac:
                                try:
                                    cac[0].place_forget()
                                except:
                                    continue
                            s.movingcac = []
                            time.sleep(1)
                            s.lost = False
                            setdinohight()
    #-------------------------------------------------------------------------------
                elif cacinfo[3] == 2:
                    if s.xpos > cacinfo[1] - 0.07 and s.xpos < cacinfo[1]:
                        if s.ypos + 0.21 > cacinfo[2]:

    # -------------------------------------------------------------------------------
                            lostimg = lost()
                            dino.configure(image=lostimg)
                            dino.place_configure(relx=s.xpos, rely=s.ypos)
                            dino.lift()
                            ground.lift()

                            frame.update()

                            for cac in s.movingcac:
                                try:
                                    cac[0].place_forget()
                                except:
                                    continue
                            s.movingcac = []
                            time.sleep(1)
                            s.lost = False
                            setdinohight()

    # -------------------------------------------------------------------------------


                elif cacinfo[3] == 3:
                    if s.xpos > cacinfo[1] - 0.075 and s.xpos < cacinfo[1]:
                        if s.ypos + 0.215 > cacinfo[2]:

    # -------------------------------------------------------------------------------
                            lostimg = lost()
                            dino.configure(image=lostimg)
                            dino.place_configure(relx=s.xpos, rely=s.ypos)
                            dino.lift()
                            ground.lift()

                            frame.update()

                            for cac in s.movingcac:
                                try:
                                    cac[0].place_forget()
                                except:
                                    continue
                            s.movingcac = []
                            time.sleep(1)
                            s.lost = False
                            setdinohight()
    # -------------------------------------------------------------------------------


                #print("CACT MOVED!")
            except Exception as e:
                print("MOVE CACT EXEPTION")
                print(traceback.format_exc())
                print(e)
                continue

        ground.lift()
        time.sleep(0.03333334)
        frame.update()#FRAMEUPDATE---FRAMEUPDATE---FRAMEUPDATE---FRAMEUPDATE---FRAMEUPDATE---FRAMEUPDATE---FRAMEUPDATE---FRAMEUPDATE---FRAMEUPDATE---
        s.updatecheck = True


except Exception as e:
    if "command" in str(e).lower():
        raise SystemExit
    if sys.platform == "win32":
        ctypes.windll.user32.ShowWindow(ctypes.windll.kernel32.GetConsoleWindow(), 1)
    print("\n\n")
    print("---" * 500)
    print("---" * 500)
    print("---" * 500)
    print(f"FATAL ERROR:\n\n{str(e)}")
    time.sleep(100)
