import threading, sys
from os import system
import time

import sys

COLORS = True


RESET = "\033[00m"

DEFAULT = "\033[39m"
BLACK = "\033[30m"
RED = "\033[31m"
GREEN = "\033[32m"
YELLOW = "\033[33m"
BLUE = "\033[34m"
MAGENTA = "\033[35m"
CYAN = "\033[36m"
LIGHT_GRAY = "\033[37m"
DARK_GRAY = "\033[90m"
LIGHT_RED = "\033[91m"
LIGHT_GREEN = "\033[92m"
LIGHT_YELLOW = "\033[93m"
LIGHT_BLUE = "\033[94m"
LIGHT_MAGENTA = "\033[95m"
LIGHT_CYAN = "\033[96m"
WHITE = "\033[97m"




global opsys
opsys = "win"
try:
    import msvcrt
except:
    opsys = "other"
    import tty, termios

class Frameclock:
    def __init__(self):
        self.lastTime = time.time() * 1000
        self.frames = 0;
        self.fps = 0
        threading1 = threading.Thread(target=self.loop)
        threading1.daemon = True
        threading1.start()
        self.skip = 0

    def getFPS(self):
        return self.fps
    def loop(self):
        while True:
            time.sleep(1)
            self.fps = self.frames
            self.frames = 0

    def tick(self, fps):
        self.frames += 1
        wait = 1000 / fps
        self.skip -= 1
        next = self.lastTime + wait
        if (next > self.lastTime):
            time.sleep(int((next - self.lastTime) / 1000))
        else:
            self.skip = (self.lastTime - next) / wait
        self.lastTime = time.time() * 1000

class Rect:
    def __init__(self, x, y, width, height):
        self.height = height
        self.width = width
        self.y = y
        self.x = x
        self.left = x
        self.right = x + width

        self.top = y
        self.bottom = y + height


    def collides(self, r):
        hoverlaps = True
        voverlaps = True
        if (self.left > r.right) or (self.right < r.left):
            hoverlaps = False
        if (self.top < r.bottom) or (self.bottom > r.top):
            voverlaps = False

        return hoverlaps and voverlaps
    def hasPoint(self, x, y):
        if (x < self.right and x > self.left and y < self.bottom and y > self.top):
            return True
        return False


class KeyLogger:
    def __init__(self, screen):
        self.screen = screen
        self.listeners = []
        self.keys = {" " : False}
        threading1 = threading.Thread(target=self.loop)
        threading1.daemon = True
        threading1.start()

    def loop(self):
        while True:
            time.sleep(0.01)
            self.readKeys()

    def addListener(self, listener):
        self.listeners.append(listener)

    def readKeys(self):
        global opsys
        if (opsys == "win"):
            ch = msvcrt.getch().decode("utf-8").lower()
        else:
            fd = sys.stdin.fileno()
            old_settings = termios.tcgetattr(fd)
            tty.setraw(sys.stdin.fileno())
            ch = sys.stdin.read(1)
        for l in self.listeners:
            l(ch)

class Sprite:
    def __init__(self, x, y, image, name):
        self.image = image

        self.rect = Rect(x, y, len(image[0]), len(image))
        self.x = x
        self.y = y
        self.velocity = []
        self.width = self.rect.width
        self.height = self.rect.height
        self.delete = False
        self.update = self.updateMethod
        self.name = name
        self.life = 0
    def updateMethod(self, star):
        pass
    def move(self, x, y):
        self.x += x
        self.y += y
        self.rect = Rect(self.x, self.y, len(self.image[0]), len(self.image))
        return self.rect
    def remove(self):
        self.delete = True;



class Renderer:
    def __init__(self, width, height):
        self.grid = []
        for i in range(0, 1 + height):
            self.grid.append(" " * width)
        self.rect = Rect(0, 0, width, height)

    def rect(self, rect, char="#"):
        try:
            for y in range(rect.y, rect.y + rect.height - 1):
                xpos = []
                for x in range(rect.x, rect.x + rect.width - 1):
                    xpos.append(x)
                row = self.grid[y]
                newRow = ""
                i = 0
                while i < len(row):
                    if i in xpos:
                        newRow = newRow + char
                    else:
                        newRow = newRow + row[i]
                    i += 1
                self.grid[y] = newRow
        except:
            pass
    def text(self, x, y, text):
        i = 0
        for c in text:
            self.point(x + i, y, c)
            i+=1
    def point(self, x, y, char="#"):
        try:
            if char != " ":
                row = self.grid[y]
                newRow = ""
                i = 0
                while i < len(row):
                    if i == x:
                        newRow = newRow + char
                    else:
                        newRow = newRow + row[i]
                    i += 1
                self.grid[y] = newRow
        except:
            pass

    def border(self, rect, char="#"):
        try:
            for y in range(rect.y, rect.y + rect.height + 1):
                for x in range(rect.x, rect.x + rect.width + 1):
                    row = self.grid[y]
                    newRow = ""
                    i = 0
                    if (x == rect.x or x == rect.x + rect.width) or (y == rect.y or y == rect.y + rect.height):
                        while i < len(row):
                            if x == i:
                                newRow = newRow + char
                            else:
                                newRow = newRow + row[i]
                            i += 1
                        self.grid[y] = newRow
        except:
            pass

    def frame(self, rect):

        for x in range(rect.x, rect.x + rect.width -1):
            self.point(x, rect.y, "═")
        for x in range(rect.x, rect.x + rect.width -1):
            self.point(x, rect.y + rect.height -1, "═")

        for y in range(rect.y, rect.y + rect.height -1):
            self.point(rect.x, y, "║")
        for y in range(rect.y, rect.y + rect.height -1):
            self.point(rect.x + rect.width -1, y, "║")

        self.point(rect.x, rect.y, "╔")
        self.point(rect.x + rect.width -1, rect.y, "╗")
        self.point(rect.x, rect.y + rect.height -1, "╚")
        self.point(rect.x + rect.width -1, rect.y + rect.height -1, "╝")

    def move(self, x, y):
        grid = self.grid
        if y > 0:
            del grid[len(grid) - 1]
            grid.insert(0, (" " * self.width))
        if y < 0:
            del grid[0]
            grid.append(" " * self.width)

        if x < 0:
            i = 0
            for l in grid:
                grid[i] = l[-x:] +( " "  * abs(x))
                i += 1
        if x > 0:
            i = 0
            for l in grid:
                grid[i] = (" "  * abs(x)) + l[:-(x)]
                i += 1
    def image(self, x, y, image):
        for ix in range(0, len(image[0]) ):
            for iy in range(0, len(image) ):
                # if self.rect.hasPoint(ix, iy):
                self.point(x + ix, y + iy, image[iy][ix])

    def sprite(self, sprite):
        self.image(sprite.rect.x, sprite.rect.y, sprite.image)


class Screen:
    def __init__(self, width, height, colored=True):
        self.width = width
        self.height = height
        self.colored = colored
        self.rect = Rect(0,0,width, height)
        self.draw = Renderer(width, height)

    def refresh(self, offset=[0,0], color=WHITE):

        string = ""
        if self.colored:
            string = color
        for line in self.draw.grid:
            string = string + line + "\r\n"
        # try:
        #     system('cls')
        # except:
        #     pass


        print(("\033[F" + "\b" * (self.width)) * self.height + string, end="")

        sys.stdout.flush()


    def clear(self, char=" "):
        self.draw.grid = []
        for i in range(0, self.height):
            self.draw.grid.append(char * self.width)







