import threading, time
import pygame, sys
from math import sin, cos, pi
import random

Musta = (0, 0, 0)  # Mustassa ei ole mitään valoa
Sin = (0, 0, 255)  # vain sinistä
Pun = (255, 0, 0)
Vihr = (0, 255, 0)
Maasto = (100, 120, 10)
Kelt = (255, 255, 0)
Valk = (255, 255, 255)  # valkoisessa on kaikenväristä valoa
Tausta = (160, 200, 255)

MaxHaara = 10
LCoeff = 0.95
DKulma = 0.3
DS = 0.25
Ccos = 2.0


CXW = 1800 # Ikkunan leveys pikseleinä näytöllä
CYW = 1000 # Ikkunan korkeus pikseleinä näytöllä

YW = 100.0 # Maiseman korkeus. 
XW = CXW/CYW*YW  # Maiseman leveys
SKAALA = CYW/YW

def screenxy(x, y):
    return (int(SKAALA*x+CXW/2.0), int(CYW-SKAALA*y))


def puuVari(Nhaara):
    r = 20 + (80-20)*Nhaara/MaxHaara
    g = 240 - (240-20)*Nhaara/MaxHaara
    return (r,g,0)


class oksa(threading.Thread):
    def __init__(self, paikka, tyvi, kulma, pituus, Nhaara):
        threading.Thread.__init__(self)
        self.paikka = paikka
        self.kulma = kulma
        self.pituus = pituus
        self.paksuus = 2.0 + Nhaara
        self.Nhaara = Nhaara
        self.tyvi = tyvi
        self.vasenhaara = None
        self.oikeahaara = None
        
    def run(self):
        self.kasvata(pi/2.0)
        self.piirra_w(0, 2, 0.0, True)
        kasvu.set()
        s = 0.0075
        for j in range(2):
            for k in range(100):
                self.huoju(s)
                self.piirra_w(0, 2, 0.0, False)
                time.sleep(0.05)
            s = -s
        s = -s
       
    def kasvata(self, Skulma):
        if self.Nhaara > 0 and Skulma < pi and Skulma > 0:
            pituus = LCoeff*self.pituus + random.uniform(-DS,DS)
            + Ccos*(cos(Skulma) - 0.5)
            kulma = DKulma + random.uniform(-0.05,0.05)
            self.vasenhaara = oksa(self.paikka, self, kulma, pituus, self.Nhaara-1)
            self.vasenhaara.kasvata(Skulma+kulma)
        if self.Nhaara > 0 and Skulma < pi and Skulma > 0:
            pituus = LCoeff*self.pituus + random.uniform(-DS, DS)
            + Ccos*(cos(Skulma) - 0.5)
            kulma = - DKulma + random.uniform(-0.05,0.05)
            self.oikeahaara = oksa(self.paikka, self, kulma, pituus, self.Nhaara-1)
            self.oikeahaara.kasvata(Skulma+kulma)
        else:
            self.vasenhaara = Kukka(self)
            self.oikeahaara = Kukka(self)

    def huoju(self, huojahdus):
        self.kulma = self.kulma+huojahdus/self.paksuus*self.pituus/7.0
        if not self.vasenhaara is None:
            self.vasenhaara.huoju(huojahdus)
        if not self.oikeahaara is None:
            self.oikeahaara.huoju(huojahdus)


    def piirra_w(self, x0, y0, kulma0, Wait):
        kulma = self.kulma+kulma0
        if self.tyvi is None:
            (x0, y0) = self.paikka
        x = x0 + self.pituus*cos(kulma)
        y = y0 + self.pituus*sin(kulma)
        xy1 = screenxy(x, y)
        xy0 = screenxy(x0, y0)
        pygame.draw.line(screen, puuVari(self.Nhaara),
                         xy0, xy1, int(self.paksuus))
        if Wait:
            portti.acquire()
            pygame.display.flip()
            portti.release()
#            time.sleep(0.05)
#           pygame.time.wait(10)
        if not self.vasenhaara is None:
            self.vasenhaara.piirra_w(x,y,kulma, Wait)
        if not self.oikeahaara is None:
            self.oikeahaara.piirra_w(x,y,kulma, Wait)

class Kukka:
    def __init__(self, varsi):
        self.size = varsi.pituus/20.0
        self.varsi = varsi
        self.colors = [Kelt, Sin, Pun, Kelt]

    def piirra_w(self,x,y,kulma,Wait):
        for i in range(3, 0, -1):
            xf, yf = screenxy(x-i*self.size, y+i*self.size)
            w = int(2*i*self.size*SKAALA)
            h = int(2*i*self.size*SKAALA)
            pygame.draw.ellipse(screen, self.colors[i], (xf, yf, w, h), 0)
            if Wait:
                portti.acquire()
                pygame.display.flip()
                portti.release()
#                time.sleep(0.05)
                print("kukka piirretty")
#            pygame.time.wait(10)

    def huoju(self, kulma):
        pass

class Pilvi(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        xv = random.uniform(0.1,0.9*CXW)
        ytop = random.uniform(0.1,0.7*CYW)
        w = random.uniform(0.02*CXW,0.2*CXW)
        h = max(0.2*w,random.uniform(0.02*CYW,0.025*CYW))
        self.coords = pygame.Rect(int(xv), int(ytop), int(w), int(h))

    def run(self):
        self.piirra()
        kasvu.wait()
        while True:
            if self.coords.left > CXW:
                self.coords.move_ip(-CXW-self.coords.width, random.randrange(-1,2))
            else:
                max_speed = int(8-4*self.coords.y/CYW)
                self.coords.move_ip(random.randrange(0,max_speed), random.randrange(-1,2))
    #            w0 = self.coords.width  
    #            h0 = self.coords.height
    #            w1 = min(0.2*CXW, max(0.01*CXW, w0 + random.uniform(-1,2)))
    #            h1 = min(0.2*w1,max(0.01*CYW, h0 + random.uniform(-1,2)))
    #            print(w1,h1)
                self.coords.inflate_ip(random.randrange(-1,2), 
                                       random.randrange(-1,2))
                self.coords.width = max(int(0.02*CXW),
                                        min(int(0.2*CXW),self.coords.width))
                self.coords.height = min(int(self.coords.width/5.0),
                                         max(int(0.02*CYW),self.coords.height))
            self.piirra()
            time.sleep(0.05)


    def piirra(self):
        pygame.draw.ellipse(screen, Valk, self.coords, 0)
        portti.acquire()
        pygame.display.flip()
        portti.release()
         
def maasto():
    pygame.draw.ellipse(screen, Maasto,
                        (0.4*CXW, 0.85*CYW, 0.9*CXW, CYW), 0)
    pygame.draw.ellipse(screen, Musta,
                        (0.4*CXW, 0.85*CYW, 0.9*CXW, CYW), 2)
    pygame.draw.ellipse(screen, Maasto,
                        (-0.1*CXW, 0.8*CYW, 0.8*CXW, 0.8*CYW), 0)
    pygame.draw.ellipse(screen, Musta,
                        (-0.1*CXW, 0.8*CYW, 0.8*CXW, 0.8*CYW), 2)
 

def lopetus():
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            pygame.quit()
            sys.exit()    

# # # # # # # # # # # # # # # # # # # # # # # # # # #
# Pääohjelma alkaa tästä
# # # # # # # # # # # # # # # # # # # # # # # # # # #

def main():

#    screen = pygame.display.set_mode((CXW, CYW))
    pygame.display.set_caption("puut")
    pygame.init()
#    clock = pygame.time.Clock()
    random.seed()
    
    screen.fill(Tausta)
    
    #pygame.draw.ellipse(screen, Maasto, (-0.1*CXW, 0.8*CYW, 1.2*CXW, 1.2*CYW), 0)
    
    pilvet = []
    
    for i in range(100):
        pilvet.append(Pilvi())
    
    for pilvi in pilvet:
#        pygame.time.wait(50)
        time.sleep(0.05)
        pilvi.start()
#        pygame.display.flip()
     
#    pygame.time.wait(500)
    
    maasto()
    portti.acquire()
    pygame.display.flip()
    portti.release()
    
#    pygame.time.wait(500)
    
    puut = []
    
    puut.append(oksa((-60, 15), None, pi/2.0+0.1, 5.0, MaxHaara-2))
    puut.append(oksa((50, 10), None, pi/2.0-0.1, 7.0, MaxHaara-1))
    puut.append(oksa((-10, 4), None, pi/2.0, 9.0, MaxHaara))
    
    for puu in puut:
        puu.start()

    kasvu.wait()
    
#    pygame.time.wait(500)
    
    loppu = False
    while not loppu:
    #    for event in pygame.event.get():
    #        if event.type == pygame.QUIT:
    #            loppu = True
    #        if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
    #            loppu = True
    
        screen.fill(Tausta)
#                for pilvi in pilvet:
#                    pilvi.liiku()
#                    pilvi.piirra(screen)
        maasto()
#                for puu in puut:
#                    puu.huoju(s)
#                    puu.piirra_w(0, 2, 0.0, False,screen)
        portti.acquire()
        pygame.display.flip()
        portti.release()
        lopetus()
        time.sleep(0.02)
#        pygame.time.wait(20)
#            s = -s
#        s = -s
    
    pygame.quit()

if __name__ == "__main__":

    screen = pygame.display.set_mode((CXW, CYW))
    
    kasvu = threading.Event()
    portti = threading.Lock()
    
#    portti.acquire()
#    portti.release()
    
    main()
