import pygame
 
class tinfnt(object):
    def __init__(self):
        image_file = "tinyfont.png"
        self.image = pygame.image.load(image_file)
        self.image.set_colorkey((255,255,255))
        self.rect = {}
        tmp = pygame.Rect(0,0,6,6)
        for letter in range(95):
            self.rect[letter] = tmp.move(letter*6,0)

    def get(self,name,num=0):    return self.rect[name]

    def line_image(self,text):
        len_text = len(text)
        tmp_image = pygame.Surface((len_text*6,6))
        tmp_image.fill((255,255,255))
        tmp_image.set_colorkey((255,255,255))
        for stroke in range(len_text):
            tmp_image.blit(self.image,(stroke*6,0,6,6),self.rect[ord(text[stroke])-32])
        return tmp_image

    def write(self,image,dest,text):
        row = 0
        dest = pygame.Rect(dest,(0,0))
        for line in text.split("\n"):
            tmp_dest = dest.move (0,row)
            image.blit(self.line_image(line),tmp_dest)
            row += 6

    def prnt(self,image,text,col,row):
        dest = pygame.Rect((0,0),(0,0))
        lines = text.split("\n")
        i = 0
        while i < len(lines):
            line = lines[i]
            len_line = len(line)
            if len_line > col:
                lines[i] = line[col:len_line]
                lines.insert(i,line[0:col])
            i += 1
        len_lines = len(lines)
        if len_lines >= row:
            lines = lines[len_lines-row:len_lines]
        i=0
        for line in lines:
            tmp_dest = dest.move (0,i*6)
            image.blit(self.line_image(line),tmp_dest)
            i += 1

typewriter = tinfnt()

class tiny_touch(pygame.sprite.Sprite):
    def __init__(self,line,pos):
        (x,y) = pos
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((len(line)*6+2,8))
        self.rect = self.image.get_rect().move(x,y)
        self.image.set_colorkey((255,255,255))
        self.image.fill((255,255,255))
        typewriter.write(self.image,(2,2),line)
        self.function = line

    def highlight(self, flag):
        if flag:
            pygame.draw.rect(self.image,(0,0,255),(0,0,self.rect.w,self.rect.h),1)
        else:
            pygame.draw.rect(self.image,(255,255,255),(0,0,self.rect.w,self.rect.h),1)

class tiny_keyboard(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((128,40))
        #self.image.set_colorkey((255,255,0))
        self.rect = self.image.get_rect()
        self.touchs = {}
        self.sheet = ""
        self.caps = False
        self.maj = False
        self.last_key = None

        tmp = "1234567890qwertyuiopasdfghjklzxcvbnm?"
        for col in range(24,104,8):
            self.touchs[tmp[0]] = tiny_touch(tmp[0],(col,0))
            tmp = tmp[1:]
        for col in range(24,104,8):
            self.touchs[tmp[0]] = tiny_touch(tmp[0],(col,8))
            tmp = tmp[1:]
        for col in range(28,96,8):
            self.touchs[tmp[0]] = tiny_touch(tmp[0],(col,16))
            tmp = tmp[1:]
        for col in range(32,96,8):
            self.touchs[tmp[0]] = tiny_touch(tmp[0],(col,24))
            tmp = tmp[1:]
        self.touchs["SPACE"] = (tiny_touch("SPACE",(47,32)))
        self.touchs["RET"] = (tiny_touch("RET",(100,16)))
        self.touchs["RMAJ"] = (tiny_touch("MAJ",(96,24)))
        self.touchs["LMAJ"] = (tiny_touch("MAJ",(10,24)))
        self.touchs["CAPS"] = (tiny_touch("CAPS",(0,16)))
        self.touchs["TAB"] = (tiny_touch("TAB",(0,8)))
        self.touchs["BSP"] = (tiny_touch("BSP",(104,0)))
        self.touchs["DEL"] = (tiny_touch("DEL",(104,8)))
        self.touchs["ESC"] = (tiny_touch("ESC",(0,0)))

    def reset(self):
        self.sheet = ""
        self.caps = False
        self.maj = False
        self.last_key = None
        key = None
    
    def update(self):
        if self.maj:
            self.touchs["LMAJ"].highlight(True)
            self.touchs["RMAJ"].highlight(True)
        else:
            self.touchs["LMAJ"].highlight(False)
            self.touchs["RMAJ"].highlight(False)
        if self.caps:
            self.touchs["CAPS"].highlight(True)
        else:
            self.touchs["CAPS"].highlight(False)
        self.image.fill((255,255,255))
        for touch in self.touchs:
            self.image.blit(self.touchs[touch].image,self.touchs[touch].rect)

    def click(self,pos):
        (x,y) = pos
        for button in self.touchs:
            if self.touchs[button].rect.collidepoint((x,y)):
                stroke = self.touchs[button].function
                if stroke == "SPACE":
                    self.sheet += " "
                elif stroke == "RET":
                    self.sheet += "\n"
                elif stroke == "ESC":
                    pass
                elif stroke == "TAB":
                    self.sheet += "    "
                elif stroke == "BSP":
                    self.sheet = self.sheet[0:len(self.sheet)-1]
                elif stroke == "DEL":
                    self.sheet = self.sheet[1:len(self.sheet)]
                elif stroke == "MAJ":
                    self.maj = not self.maj
                elif stroke == "CAPS":
                    self.caps = not self.caps
                else:
                    if self.maj == True:
                        stroke = stroke.upper()
                        self.maj = False
                    if self.caps == True:
                        stroke = stroke.swapcase()
                    self.sheet += stroke
                self.last_key = stroke

    def key_down(self, key):
        if key == "space":
            self.sheet += " "
            key = "SPACE"
        elif key == "return":
            self.sheet += "\n"
            key = "RET"
        elif key == "tab":
            self.sheet += "    "
            key = "TAB"
        elif key == "escape":
            key = "ESC"
        elif key == "delete":
            self.sheet = self.sheet[1:len(self.sheet)]
            key = "DEL"
        elif key == "backspace":
            self.sheet = self.sheet[0:len(self.sheet)-1]
            key = "BSP"
        elif key == "caps lock":
            self.caps = not self.caps
            key = "CAPS"
        elif key == "left shift" or key == "right shift":
            self.maj = not self.maj
            key = "MAJ"
        else:
            if self.maj == True:
                key = key.upper()
                self.maj = False
            if self.caps == True:
                key = key.swapcase()
            self.sheet += key
        self.last_key = key

#====================================================

class tiny_clock(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.name = "Clock"
        import time,math
        self.time = time.localtime
        self.sin = math.sin
        self.cos = math.cos
        self.image = pygame.Surface((128,128))
        self.rect = pygame.Rect(21,21,32,32)


    def pole(self,rad,ray):
        return ( 64+ray*self.sin(rad) , 68-ray*self.cos(rad))

    def update(self):
        self.image.fill((255,255,255))
        pygame.draw.circle(self.image, (0,0,0), (64,68), 56, 6)
        tmp = self.time()
        hour, minute, second = tmp[3], tmp[4], tmp[5]
        pygame.draw.line(self.image, (255,0,0), (64,68), self.pole(hour*6.2832/12,30), 6)
        pygame.draw.line(self.image, (0,255,0), (64,68), self.pole(minute*6.2832/60,40), 5)
        pygame.draw.line(self.image, (0,0,255), (64,68), self.pole(second*6.2832/60,50), 3)
        pygame.draw.polygon(self.image, (0,0,0), ((64,62),(59,71),(69,71)) )

    def click(self,pos):
        pass
    
    def stroke(self,key):
        pass

class tiny_calendar(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.name = "Calendar"
        import time,math,calendar
        self.time = time.localtime
        self.cal = calendar.TextCalendar(6)
        self.month = self.cal.formatmonth
        self.image = pygame.Surface((128,128))
        self.rect = pygame.Rect(74,21,32,32)

    def update(self):
        self.image.fill((255,255,255))
        pygame.draw.rect(self.image, (192,255,192), (2,79,124,7))
        pygame.draw.rect(self.image, (192,192,255), (2,92,16,48))
        pygame.draw.rect(self.image, (255,192,192), (20,92,16,48))
        pygame.draw.rect(self.image, (192,192,255), (38,92,16,48))
        pygame.draw.rect(self.image, (255,192,192), (54,92,16,48))
        pygame.draw.rect(self.image, (192,192,255), (72,92,16,48))
        pygame.draw.rect(self.image, (255,192,192), (90,92,16,48))
        pygame.draw.rect(self.image, (192,192,255), (108,92,16,48))
        tmp = self.time()
        year, month, day = tmp[0], tmp[1], tmp[2]
        typewriter.write(self.image,(4,80),self.month(year,month))
        

    def click(self,pos):
        pass
    
    def stroke(self,key):
        pass

class tiny_terminal(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.name = "Terminal"
        self.image = pygame.Surface((128,128))
        self.rect = pygame.Rect(21,74,32,32)
        self.keyb = tiny_keyboard()
        self.termout = pygame.Surface((128,88))

    def update(self):
        self.image.fill((255,255,255))
        self.keyb.update()
        self.image.blit(self.keyb.image,(0,96))
        self.termout.fill((255,255,255))
        typewriter.prnt(self.termout,self.keyb.sheet,21,14)
        self.image.blit(self.termout,(0,8))

    def click(self,pos):
        (x,y) = pos
        self.keyb.click((x,y-96))
    
    def stroke(self,key):
        self.keyb.key_down(key)

class tiny_menu(pygame.sprite.Sprite):
    def __init__(self,apps):
        pygame.sprite.Sprite.__init__(self)
        self.name = "Tiny OS"
        self.image = pygame.Surface((128,128))
        self.rect = pygame.Rect(0,0,8,8)
        self.apps = apps
        self.select = None

    def update(self):
        self.image.fill((255,255,255))
        if self.select == None:
            for app in self.apps:
                app.update()
                icon = pygame.transform.scale(app.image, (32, 32))
                self.image.blit(icon,app.rect)
                pygame.draw.rect(self.image, (0,0,0), app.rect,2)
        else:
            app = self.select
            app.update()
            self.image.blit(app.image,(0,0))
            pygame.draw.rect(self.image, (64,64,255), (0,0,128,8))
            typewriter.write(self.image,((128-len(app.name)*6)/2,2),app.name)
            pygame.draw.polygon(self.image,(255,255,255),((1,1),(7,1),(1,7)),1)
        
    def click(self,pos):
        (x,y) = pos
        if self.select == None:
            for app in self.apps:
                if app.rect.collidepoint(x,y):
                    self.select = app
        else:
            if self.rect.collidepoint(x,y):
                self.select = None
            else:
                self.select.click((x,y))
    
    def stroke(self,key):
        if self.select:
            self.select.stroke(key)


#====================================================

if __name__ == "__main__":
    tiny_term = tiny_terminal()
    tiny_cal = tiny_calendar()
    tiny_clk = tiny_clock()
    tiny_main = tiny_menu([tiny_clk,tiny_cal,tiny_term])
    
    current = tiny_main

    end = False
    pygame.init()
    pygame.display.set_caption("Tiny-Os")
    pygame.mouse.set_visible(1)
    pygame.event.set_allowed(None)
    pygame.event.set_allowed([pygame.QUIT,pygame.KEYDOWN,pygame.MOUSEBUTTONDOWN])
    screen = pygame.display.set_mode((128, 128))
    clock = pygame.time.Clock()
    
    #screen = pygame.Surface((128,128))
    #zoomed = pygame.display.set_mode((384, 384))
    
    while end == False :
        clock.tick(15)
        #======================================================
        screen.fill((255,255,255))
        
        current.update()
        screen.blit(current.image,(0,0))
        
        #zoomed.blit(pygame.transform.scale(screen, (384, 384)),(0,0))
        #======================================================
        pygame.display.flip()
        event = pygame.event.poll()
        if event.type == pygame.QUIT:
            end = True
        elif event.type == pygame.MOUSEBUTTONDOWN:
            x,y = event.pos
            current.click((x,y))
            #current.click((x/3,y/3))
            pass
        elif event.type == pygame.KEYDOWN:
            current.stroke(pygame.key.name(event.key))
            pass
