import pyglet
from pyglet.gl import *
from pyglet.window import key,mouse
import pyglet.graphics
from framework import *
from widget import *
import random,math


class MagicSprite(SpriteAnim):

    def __init__(self,sprite):
        self.orx = Var(0)
        self.ory = Var(0)
        self.ogx = Var(0)
        self.ogy = Var(0)
        self.obx = Var(0)
        self.oby = Var(0)
        SpriteAnim.__init__(self,sprite)

    def draw(self):
        orx = self.orx(); ory = self.ory()
        ogx = self.ogx(); ogy = self.ogy()
        obx = self.obx(); oby = self.oby()
        glColorMask(1,0,0,1)
        self.sprite.x += orx
        self.sprite.y += ory
        self.sprite.draw()
        glColorMask(0,1,0,1)
        self.sprite.x += ogx - orx
        self.sprite.y += ogy - ory
        self.sprite.draw()
        glColorMask(0,0,1,1)
        self.sprite.x += obx - ogx
        self.sprite.y += oby - ogy
        self.sprite.draw()
        glColorMask(1,1,1,1)
        self.sprite.x -= obx
        self.sprite.y -= oby
        

    def update(self,dt):
        self.orx.update(dt); self.ory.update(dt)
        self.ogx.update(dt); self.ogy.update(dt)
        self.obx.update(dt); self.oby.update(dt)
        SpriteAnim.update(self,dt)


class MenuControl(icuControl):

    def on_key_press(self,symbol,modifiers):
        if symbol == key.ESCAPE:
            main.winman.window.close()

    def on_mouse_press(self,x,y,button,modifiers):
        if button == mouse.LEFT:
            self.mode.start(x,y)
    

class MenuView(icuView):

    def __init__(self,mode):
        self.spr = pyglet.sprite.Sprite(pyglet.image.load("StarryNightBkg.png"))
        self.spr.y = -768
        self.sprite = MagicSprite(self.spr)
        self.sprite.ay.add([2.5],768)
        self.sprite.ay.add([2.5],512,0,[],[2.5])
        self.sprite.ogx.add([2.5],341,0,[],[2.5])
        self.sprite.obx.add([2.5],682,0,[],[2.5])
        self.sprite.ascale.add([2.5],-0.6667,0,[],[2.5])
        self.text = pyglet.text.Label("Starry Night Experiment",font_name="uni 05_53",font_size=30,x=20,y=500)
        self.text.color = (255,255,255,0)
        self.text2 = pyglet.text.Label("by Greg Lane",font_name="uni 05_53",font_size=30,anchor_x="right",x=1004,y=500)
        self.text2.color = (255,255,255,0)
        self.talpha = Var(0)
        self.talpha.add([2.0],255,0,[],[5.0])
        self.talpha2 = Var(0)
        self.talpha2.add([2.0],255,0,[],[7.0])
        self.rbox = Var(0)
        self.gbox = Var(0)
        self.bbox = Var(0)
        self.rbox.add([1.0],512,2,[],[7.0])
        self.gbox.add([1.0],512,2,[],[7.5])
        self.bbox.add([1.0],512,2,[],[8.0])
        self.rtext = Var(0)
        self.gtext = Var(0)
        self.btext = Var(0)
        self.rtext.add([1.0],255,0,[],[7.5])
        self.gtext.add([1.0],255,0,[],[8.0])
        self.btext.add([1.0],255,0,[],[8.5])
        self.textr = pyglet.text.Label("Hard",font_name="uni 05_53",font_size=60,anchor_x="center",x=170,y=300)
        self.textr.color = (255,0,0,0)
        self.textg = pyglet.text.Label("Medium",font_name="uni 05_53",font_size=60,anchor_x="center",x=512,y=300)
        self.textg.color = (0,255,0,0)
        self.textb = pyglet.text.Label("Easy",font_name="uni 05_53",font_size=60,anchor_x="center",x=853,y=300)
        self.textb.color = (0,0,255,0)

    def cutanimation(self):
        self.sprite.ay.end()
        self.sprite.ogx.end()
        self.sprite.obx.end()
        self.sprite.ascale.end()
        self.talpha.end()
        self.talpha2.end()
        self.rbox.end()
        self.gbox.end()
        self.bbox.end()
        self.rtext.end()
        self.gtext.end()
        self.btext.end()

    def update(self,dt):
        self.sprite.update(dt)
        self.talpha.update(dt)
        self.text.color = (255,255,255,int(self.talpha()))
        self.talpha2.update(dt)
        self.text2.color = (255,255,255,int(self.talpha2()))
        self.rbox.update(dt)
        self.gbox.update(dt)
        self.bbox.update(dt)
        self.rtext.update(dt)
        self.gtext.update(dt)
        self.btext.update(dt)
        self.textr.color = (255,0,0,int(self.rtext()))
        self.textg.color = (0,255,0,int(self.gtext()))
        self.textb.color = (0,0,255,int(self.btext()))

    def draw(self):
        self.sprite.draw()
        r = self.rbox(); g = self.gbox(); b = self.bbox()
        pyglet.graphics.draw(4,GL_QUADS,('v2f',(0,0,0,r,341,r,341,0)),('c4B',(128,0,0,255)*4))
        pyglet.graphics.draw(4,GL_QUADS,('v2f',(341,0,341,g,682,g,682,0)),('c4B',(0,128,0,255)*4))
        pyglet.graphics.draw(4,GL_QUADS,('v2f',(682,0,682,b,1024,b,1024,0)),('c4B',(0,0,128,255)*4))
        self.text.draw()
        self.text2.draw()
        self.textr.draw()
        self.textg.draw()
        self.textb.draw()


class MenuMode(icuMode):

    def __init__(self):
        self.control = MenuControl(self)
        self.view = MenuView(self)

    def start(self,x,y):
        if self.view.btext.active():
            self.view.cutanimation()
            return
        main.mode.pop()
        if x < 341: main.mode.append(GameMode(5.0,2.0,2.0,1000))
        elif x < 682: main.mode.append(GameMode(7.5,5.0,3.0,100))
        else: main.mode.append(GameMode(10.0,10.0,4.0,10))
        


class GameControl(icuControl):

    def on_mouse_press(self,x,y,button,modifiers):
        if button == mouse.LEFT:
            self.mode.start(x,y)

    def on_mouse_release(self,x,y,button,modifiers):
        if button == mouse.LEFT:
            self.mode.end(x,y)

    def on_mouse_drag(self,x,y,dx,dy,buttons,modifiers):
        if buttons == mouse.LEFT:
            self.mode.move(x,y)

    def on_key_press(self,symbol,modifiers):
        if symbol == key.ESCAPE:
            main.winman.window.close()
        if symbol == key.R:
            spr = self.mode.view.sprite
            spr.orx.add([random.random()*0.1+0.1],random.randint(-15,15),2,[True])
            spr.ory.add([random.random()*0.1+0.1],random.randint(-15,15),2,[True],[0.1])
        if symbol == key.G:
            spr = self.mode.view.sprite
            spr.ogx.add([random.random()*0.1+0.1],random.randint(-15,15),2,[True])
            spr.ogy.add([random.random()*0.1+0.1],random.randint(-15,15),2,[True],[0.1])
        if symbol == key.B:
            spr = self.mode.view.sprite
            spr.obx.add([random.random()*0.1+0.1],random.randint(-15,15),2,[True])
            spr.oby.add([random.random()*0.1+0.1],random.randint(-15,15),2,[True],[0.1])
        if symbol == key.V:
            spr = self.mode.view.sprite
            #spr.obx.add(1.0],random.randint(-15,15),2,[True])
            spr.oby.add([2.0],-768,2,[True])


class Brushstroke:

    circle = None

    def __init__(self):
        if self.__class__.circle == None:
            cimg = pyglet.image.load("Circle.png")
            cimg.anchor_x = cimg.width/2
            cimg.anchor_y = cimg.height/2
            self.__class__.circle = pyglet.sprite.Sprite(cimg)
            self.__class__.circle.scale = 0.2
        self.xdist = (random.randint(0,1)*2-1)*random.randint(200,1000)
        self.ydist = (random.randint(0,1)*2-1)*random.randint(200,700)
        #self.xpos = random.randint(max(10,10+self.xdist),min(1014,1014-self.xdist))
        self.xpos = random.randint(((self.xdist>0) and 10 or 10-self.xdist),((self.xdist<0) and 1014 or 1014-self.xdist))
        self.ypos = random.randint(((self.ydist>0) and 10 or 10-self.ydist),((self.ydist<0) and 758 or 758-self.ydist))
        self.numpts = (abs(self.xdist) + abs(self.ydist))//30
        xanim = AnimVar([self.numpts],self.xdist,random.randint(0,6))#,[random.randint(0,1)])
        yanim = AnimVar([self.numpts],self.ydist,random.randint(0,6))#,[random.randint(0,1)])
        self.pts = []
        for i in xrange(self.numpts):
            self.pts.append(self.xpos+xanim())
            self.pts.append(self.ypos+yanim())
            xanim.update(1.0) #xanim.cframe.bounce and 2.0 or 1.0)
            yanim.update(1.0) #yanim.cframe.bounce and 2.0 or 1.0)
        #self.colors = [(255,255,255,(float(i+1)/self.numpts)*255) for i in xrange(self.numpts)]
        #self.colors.reverse()
        self.colors = []
        rc = random.randint(128,255); gc = random.randint(128,255); bc = random.randint(128,255)
        for i in xrange(self.numpts,0,-1):
            self.colors.extend((rc,gc,bc,int(float(i)/self.numpts*200 + 55)))

        self.curcircle = 0

    def dist(self,i,x,y):
        (px,py) = self.pts[2*i:2*i+2]
        return math.hypot(x-px,y-py)

    def start(self,x,y):
        if self.dist(0,x,y) < 30:
            self.curcircle = 0
            return True
        return False

    def move(self,x,y):
        curdist = self.dist(self.curcircle,x,y)
        okay = True
        if curdist >= 30: okay = False
        if self.curcircle > 0:
            olddist = self.dist(self.curcircle-1,x,y)
            if olddist < 30 and olddist < curdist:
                self.curcircle = 0
                return False
        if self.curcircle < self.numpts-1 and not okay:
            #newdist = curdist
            #testdist = self.dist(self.curcircle+1,x,y)
            newdist = self.dist(self.curcircle+1,x,y)
            nextcir = self.curcircle + 1
            while nextcir < self.numpts-3 and not(newdist < 30 and newdist < curdist):
                nextcir += 1
                newdist = self.dist(nextcir,x,y)
            if nextcir < self.numpts-3 and newdist < 30 and newdist < curdist:
                self.curcircle = nextcir
                return True
                
        #if not okay: self.curcircle = 0
        return okay

    def end(self,x,y):
        if self.dist(self.numpts-1,x,y) < 30 or self.dist(self.numpts-2,x,y) < 30 or self.dist(self.numpts-3,x,y) < 30:
            return True
        self.curcircle = 0
        return False

    def done(self): return self.curcircle == self.numpts - 1

    def update(self,dt):
        pass            

    def draw(self,drawpts):
        """for i in xrange(self.curcircle,self.numpts):
            self.circle.x = self.pts[2*i]
            self.circle.y = self.pts[2*i+1]
            self.circle.color = self.colors[4*i:4*i+3]
            self.circle.opacity = self.colors[4*i+3]
            self.circle.draw()"""
        glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)
        #glHint(GL_LINE_SMOOTH_HINT,GL_NICEST)
        glEnable(GL_LINE_SMOOTH)
        glLineWidth(40.0)
        pyglet.graphics.draw(self.numpts,GL_LINE_STRIP,('v2f',self.pts),('c4B',self.colors))#(255,255,255,255)*self.numpts))
        glDisable(GL_LINE_SMOOTH)
        glDisable(GL_BLEND)
        glLineWidth(1.0)
        if drawpts:
            if self.curcircle >= self.numpts-3:
                self.circle.color = (0,255,0)
            else: self.circle.color = (255,255,255)
            for i in xrange(0,self.curcircle*2,2):
                self.circle.x = self.pts[i]
                self.circle.y = self.pts[i+1]
                self.circle.draw()
        #self.circle.color = (255,0,255)
        #self.circle.draw()


class GameView(icuView):

    def __init__(self,mode,nt,dc,ms,pv):
        self.mode = mode
        self.spr = pyglet.sprite.Sprite(pyglet.image.load("StarryNightBkg.png"))
        #self.spr.scale = 1.05
        #self.spr.y = -768
        self.sprite = MagicSprite(self.spr)
        #self.sprite.ay.add([2.5],768)
        #self.sprite.ay.add([2.5],512,0,[],[2.5])
        #self.sprite.ogx.add([2.5],341,0,[],[2.5])
        #self.sprite.obx.add([2.5],682,0,[],[2.5])
        #self.sprite.ascale.add([2.5],-0.6667,0,[],[2.5])
        self.nexttime = nt #wait seconds between brushstrokes
        self.deathcount = dc
        self.maxspeed = ms
        self.pointvalue = pv
        self.curtime = 1.0 #wait until next brushstroke
        self.score = 0
        self.strokes = []
        self.curbs = None
        self.scoretext = pyglet.text.Label("Score: %d"%self.score,font_name="uni 05_53",font_size=30,x=5,y=5)
        self.fader = Var(0)

    def update(self,dt):
        if not len(self.strokes):
            self.curtime = min(self.curtime,1.0)
        self.curtime -= dt
        if self.curtime <= 0.0:
            self.strokes.append(Brushstroke())
            self.curtime = self.nexttime
            self.nexttime = max(self.maxspeed,self.nexttime-0.5)
        self.sprite.update(dt)
        #for bs in self.strokes: bs.update()
        self.scoretext.text = "Score: %d"%self.score
        roff = -768*(max(0,(len(self.strokes)-1))/self.deathcount)
        if self.sprite.ory.offset != roff:
            #self.sprite.ory.cut()
            self.sprite.ory.movto([min(self.nexttime,8.0)],roff,3)
        if roff <= -768:
            self.sprite.ogx.movto([3.0],-1024,1)
            self.sprite.obx.movto([3.0],1024,1)
            self.fader.movto([2.0],255,0,[],[1.0])
            self.mode.dying = True
        if self.mode.dying: 
            self.fader.update(dt)

    def draw(self):
        self.sprite.draw()
        for bs in self.strokes: bs.draw(bs == self.curbs)
        if self.mode.dying:
            glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)
            pyglet.graphics.draw(4,GL_QUADS,('v2f',(0,0,0,768,1024,768,1024,0)),('c4B',(0,0,0,int(self.fader()))*4))
            glDisable(GL_BLEND)
        self.scoretext.draw()

    def start(self,x,y):
        for bs in self.strokes:
            if bs.start(x,y):
                self.curbs = bs
                return

    def move(self,x,y):
        if self.curbs:
            if not self.curbs.move(x,y):
                if self.curbs.end(x,y):
                    self.score += self.pointvalue
                    self.strokes.remove(self.curbs)
                else:
                    self.terribleanim()
                    self.score -= self.pointvalue/2
                self.curbs = None

    def end(self,x,y):
        if self.curbs:
            if self.curbs.end(x,y):
                self.score += self.pointvalue
                self.strokes.remove(self.curbs)
            else:
                self.terribleanim()
                self.score -= self.pointvalue/2
        self.curbs = None

    def terribleanim(self):
        spr = self.sprite
        spr.orx.add([random.random()*0.1+0.1],random.randint(-15,15),2,[True])
        spr.ory.add([random.random()*0.1+0.1],random.randint(-15,15),2,[True],[0.1])
        spr.ogx.add([random.random()*0.1+0.1],random.randint(-15,15),2,[True])
        spr.ogy.add([random.random()*0.1+0.1],random.randint(-15,15),2,[True],[0.1])
        spr.obx.add([random.random()*0.1+0.1],random.randint(-15,15),2,[True])
        spr.oby.add([random.random()*0.1+0.1],random.randint(-15,15),2,[True],[0.1])

    def destroy(self):
        self.sprite.sprite.delete()


class GameMode(icuMode):

    def __init__(self,nt,dc,ms,pv):
        self.control = GameControl(self)
        self.view = GameView(self,nt,dc,ms,pv)
        self.dying = False

    def update(self,dt):
        if self.dying and not self.view.sprite.ogx.active():
            return
        #    self.gotomenu()
        self.view.update(dt)

#    def draw(self):
#        self.view.draw()

    def gotomenu(self):
        self.view.destroy()
        main.mode.pop()
        main.mode.append(MenuMode())

    def start(self,x,y):
        if not self.dying: self.view.start(x,y)
        else: self.gotomenu()
    def move(self,x,y):
        if not self.dying: self.view.move(x,y)
    def end(self,x,y):
        if not self.dying: self.view.end(x,y)

main.mode.append(MenuMode())
pyglet.app.run()
