import pygame, sys,os ,pickle
from pygame.locals import *
from random import *
from pickle import *

pygame.init()
if not pygame.font:     print('Warning, fonts disabled')
if not pygame.mixer:     print('Warning, sound disabled')

window = pygame.display.set_mode((160,160))
screen = pygame.Surface((160,160)).convert()
font = pygame.font.Font(None,20)
clock = pygame.time.Clock()
pygame.mouse.set_visible(1)
pygame.display.set_caption("ku")

########################################################################
#######################base function####################################
########################################################################


########################################################################
#######################image building###################################
########################################################################

image_score = []
for combo in  range(21) :
    image = font.render(str(combo),0,(255,128,128),(255,255,255)).convert()
    image.set_colorkey(image.get_at((0,0)), RLEACCEL)
    image_score.append(image)

def blok_build(color):
    image = pygame.Surface((10,10)).convert()
    pygame.draw.rect(image,color,pygame.Rect(1,1,8,8),0)
    image.set_colorkey((255,255,255), RLEACCEL)
    return image

try:
    background = pygame.image.load('clickeux_0,03.png').convert()
except pygame.error:
    background = pygame.Surface((160,160)).convert()
    background.fill((255,255,255))

try:
    single_scale = pygame.image.load((os.path.join('data', 'single_scale.png'))).convert()
except pygame.error:
    single_scale = font.render("1x",0,(0,0,0),(255,255,255)).convert()
single_scale.set_colorkey(single_scale.get_at((0,0)), RLEACCEL)

try:
    double_scale = pygame.image.load((os.path.join('data', 'double_scale.png'))).convert()
except pygame.error:
    double_scale = font.render("2x",0,(0,0,0),(255,255,255)).convert()
double_scale.set_colorkey(double_scale.get_at((0,0)), RLEACCEL)

try:
    quad_scale = pygame.image.load((os.path.join('data', 'quad_scale.png'))).convert()
except pygame.error:
    quad_scale = font.render("4x",0,(0,0,0),(255,255,255)).convert()
quad_scale.set_colorkey(quad_scale.get_at((0,0)), RLEACCEL)

try:
    dead = pygame.image.load((os.path.join('data', 'dead.png'))).convert()
except pygame.error:
    dead = blok_build((140,140,140))
dead.set_colorkey((255,255,255), RLEACCEL)

try:
    image_new_game = pygame.image.load((os.path.join('data', 'new_game.png'))).convert()
except pygame.error:
    image_new_game = font.render("new_game",0,(255,0,0),(255,255,255)).convert()
image_new_game.set_colorkey((255,255,255), RLEACCEL)
    


################################################################################################
##################################mouse sprite##################################################
################################################################################################

class spr_mice(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.rect = pygame.Rect(0,0,0,0)
        self.screen_do = None
        self.mouse_do = None

    def update(self):
        (self.rect.x, self.rect.y) = pygame.mouse.get_pos()

spr_mice = spr_mice()

##################################################################################################
###################################THOSE BLOK#####################################################
##################################################################################################

new_grp_blok = pygame.sprite.RenderUpdates()
grp_blok = pygame.sprite.RenderUpdates()

matrix_blok = []
for x in range(10):
    matrix_blok.append([])
    for y in range(17):
        matrix_blok[x].append(None)

class spr_blok(pygame.sprite.Sprite):
    def __init__(self, xpos, ypos, image, group, target):
        pygame.sprite.Sprite.__init__(self)
        self.image = image
        self.rect = self.image.get_rect().move(xpos,ypos)
        self.xdest, self.ydest = xpos,ypos
        self.group = group
        self.do = self.collapse
        self.target = target
        self.combo = 0
        self.matrix = matrix_blok
        self.xpos, self.ypos = xpos/10, ypos/10
        self.matrix[self.xpos][self.ypos] = self

    def update(self):
        self.do()

    def jump(self):
        if self.ypos > 0 :
            if self.matrix[self.xpos][self.ypos - 1] != None:
                self.matrix[self.xpos][self.ypos - 1].do = self.matrix[self.xpos][self.ypos - 1].jump
            elif self.matrix[self.xpos][self.ypos - 1] == None:
                self.matrix[self.xpos][self.ypos] = None
                self.ypos -= 1
                self.matrix[self.xpos][self.ypos] = self
                self.do = self.collapse

    def collapse(self):
        if self.rect.x < self.xdest:    xmove = 5
        elif self.rect.x > self.xdest:    xmove = -5
        else:                xmove = 0
        if self.rect.y < self.ydest:    ymove = 5
        elif self.rect.y > self.ydest:    ymove = -5
        else:                ymove = 0
        self.rect.move_ip(xmove,ymove)
        if self.ypos < 14:
            if self.matrix[self.xpos][self.ypos + 1] == None:
                self.matrix[self.xpos][self.ypos] = None
                self.ypos += 1
                self.matrix[self.xpos][self.ypos] = self
        self.xdest, self.ydest =  self.xpos*10, self.ypos*10

    def clicked(self):
        if self.ypos < 15:
            if self.ypos > 0 :  self.top = self.matrix[self.xpos][self.ypos-1]
            else:               self.top = None
            if self.xpos > 0 :  self.left = self.matrix[self.xpos-1][self.ypos]
            else:               self.left = None
            if self.ypos < 14 : self.bottom = self.matrix[self.xpos][self.ypos+1]
            else:               self.bottom = None
            if self.xpos < 9 :  self.right = self.matrix[self.xpos+1][self.ypos]
            else:               self.right = None
  
        for side in [(self.left),(self.right),(self.top),(self.bottom)]:
            if side != None:
                if side.image == self.image:
                    side.do = side.clicked
                    side.combo += 1
                    self.combo += 1
                    self.combo = side.combo = side.combo + self.combo
                    
                if self.combo > 20 :
                    self.combo = 20
                if self.combo <= 1:     #only 3 or more should be scored
                    self.do = self.collapse
                else:
                    self.image = image_score[self.combo]
                    self.matrix[self.xpos][self.ypos] = None
                    self.remove(self.group)
                    self.add(self.target)
                    self.do = self.score
        else:
                self.do = self.collapse

    def score(self):
        if (self.rect.x, self.rect.y) != (120,20) :
            self.rect.y += 5 * (20 - self.rect.y) / (120 - self.rect.x)
            self.rect.x += 5

class spr_dead(pygame.sprite.Sprite):
    def __init__(self,xpos,ypos,group_blok,matrix_blok):
        pygame.sprite.Sprite.__init__(self)
        self.image = dead
        self.rect = self.image.get_rect().move(xpos*10,ypos*10)
        self.matrix = matrix_blok
        self.xpos, self.ypos = xpos, ypos
        self.matrix[self.xpos][self.ypos] = self
        self.add(group_blok)

    def update(self):
        pass

    def draw(self):
        pass

###############################################################################################
#############################scaler sprite#####################################################
###############################################################################################

class spr_single(pygame.sprite.Sprite):
    def __init__(self,xpos,ypos, mouse):
        pygame.sprite.Sprite.__init__(self)
        self.image = single_scale
        self.rect = self.image.get_rect().move(xpos,ypos)
        self.mouse = mouse

    def scale_screen(self,screen,window):
        window.blit(screen,(0,0))

    def scale_mouse(self,mouse):
        pass

    def click(self):
        window = pygame.display.set_mode((160,160))
        self.mouse.mouse_do = self.scale_mouse
        self.mouse.screen_do = self.scale_screen

class spr_double(pygame.sprite.Sprite):
    def __init__(self,xpos,ypos, mouse):
        pygame.sprite.Sprite.__init__(self)
        self.image = double_scale
        self.rect = self.image.get_rect().move(xpos,ypos)
        self.mouse = mouse

    def scale_screen(self,screen,window):
        scaled = pygame.transform.scale2x(screen)
        window.blit(scaled,(0,0))

    def scale_mouse(self,mouse):
        mouse.rect.x, mouse.rect.y = mouse.rect.x/2, mouse.rect.y/2

    def click(self):
        window = pygame.display.set_mode((320,320))
        self.mouse.mouse_do = self.scale_mouse
        self.mouse.screen_do = self.scale_screen

class spr_quad(pygame.sprite.Sprite):
    def __init__(self,xpos,ypos, mouse):
        pygame.sprite.Sprite.__init__(self)
        self.image = quad_scale
        self.rect = self.image.get_rect().move(xpos,ypos)
        self.mouse = mouse

    def scale_screen(self,screen,window):
        scaled = pygame.transform.scale2x(screen)
        scaled = pygame.transform.scale2x(scaled)
        window.blit(scaled,(0,0))

    def scale_mouse(self,mouse):
        mouse.rect.x, mouse.rect.y = mouse.rect.x/4, mouse.rect.y/4

    def click(self):
        window = pygame.display.set_mode((640,640))
        self.mouse.mouse_do = self.scale_mouse
        self.mouse.screen_do = self.scale_screen


spr_single = spr_single(111,0, spr_mice)
spr_double = spr_double(128,0, spr_mice)
spr_quad = spr_quad(145,0, spr_mice)
grp_button = pygame.sprite.RenderUpdates((spr_single, spr_double, spr_quad))

#############################################################################################
################################SCORE SPRITE#################################################
#############################################################################################

grp_combo = pygame.sprite.RenderUpdates()

class spr_combo(pygame.sprite.Sprite):
    def __init__(self,xpos,ypos,group):
        pygame.sprite.Sprite.__init__(self)
        self.score = self.old = 0
        self.group = group
        self.image = font.render(str(0),0,(255,128,128),(255,255,255)).convert()
        self.image.set_colorkey(self.image.get_at((0,0)), RLEACCEL)
        self.rect = self.image.get_rect().move(xpos,ypos)
        self.xpos, self.ypos = xpos, ypos

    def update(self):
        if self.score != self.old :
            self.image = font.render(str(self.score),0,(255,128,128),(255,255,255)).convert()
            self.rect = self.image.get_rect().move(self.xpos,self.ypos)
            self.image.set_colorkey(self.image.get_at((0,0)), RLEACCEL)
        self.old = self.score
        for sprite in pygame.sprite.spritecollide(self, self.group, False) :
            self.score += sprite.combo
            sprite.kill()

    def click(self):
        pass

spr_combo = spr_combo(111,20,grp_combo)
grp_button.add(spr_combo)

class name(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)

class high_score(pygame.sprite.Sprite):
    def __init__(self,xpos,ypos):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((58,100)).convert()
        self.image.fill((255,255,255))
        self.image.set_colorkey(self.image.get_at((0,0)), RLEACCEL)
        self.rect = self.image.get_rect().move(xpos,ypos)
        try:
            file_score = open('clickeur','rb')
            self.hall_of_fame = pickle.load(file_score)
            file_score.close()
        except IOError:
            file_score = open('clickeur','wb')
            self.hall_of_fame = []
            pickle.dump(self.hall_of_fame,file_score)
            file_score.close()
        self.build()
                    
        def build(self):
            self.image.fill((255,255,255))
            if len(self.hall_of_fame) >= 1:
                (first_score , first_name) = self.hall_of_fame[len(self.hall_of_fame)-1]
                if len(self.hall_of_fame) >= 2:
                    second_score, second_name = self.hall_of_fame[len(self.hall_of_fame)-2]
                    if len(self.hall_of_fame) >= 3:
                        third_score, third_name = self.hall_of_fame[len(self.hall_of_fame)-3]
                        if len(self.hall_of_fame) >= 4:
                            fourth_score, fourth_name = self.hall_of_fame[len(self.hall_of_fame)-4]
                            if len(self.hall_of_fame) >= 5:
                                fifth_score, fifth_name = self.hall_of_fame[len(self.hall_of_fame)-5]
                            else:
                                fifth_score, fifth_name = 0,'no_entry'
                        else:
                             fourth_score, fourth_name = 0,'no_entry'
                             fifth_score, fifth_name = 0,'no_entry'
                    else:
                        third_score, third_name = 0,'no_entry'
                        fourth_score, fourth_name = 0,'no_entry'
                        fifth_score, fifth_name = 0,'no_entry'
                else:
                    second_score, second_name = 0,'no_entry'
                    third_score, third_name = 0,'no_entry'
                    fourth_score, fourth_name = 0,'no_entry'
                    fifth_score, fifth_name = 0,'no_entry'
            else:
                first_score , first_name = 0,'no_entry'
                second_score, second_name = 0,'no_entry'
                third_score, third_name = 0,'no_entry'
                fourth_score, fourth_name = 0,'no_entry'
                fifth_score, fifth_name = 0,'no_entry'
                    
            first_one = font.render(str(first_score),0,(0,0,128),(0,0,0)).convert()
            first_one.set_colorkey((0,0,0), RLEACCEL)
            self.image.blit(first_one,(1,0))

            second_one = font.render(str(second_score),0,(0,0,128),(0,0,0)).convert()
            second_one.set_colorkey((0,0,0), RLEACCEL)
            self.image.blit(second_one,(1,20))

            third_one = font.render(str(third_score),0,(0,0,128),(0,0,0)).convert()
            third_one.set_colorkey((0,0,0), RLEACCEL)
            self.image.blit(third_one,(1,40))

            fourth_one = font.render(str(fourth_score),0,(0,0,128),(0,0,0)).convert()
            fourth_one.set_colorkey((0,0,0), RLEACCEL)
            self.image.blit(fourth_one,(1,60))
   
                    
    def update(self):
        pass

    def click(self):
            pass

    def new_entry(self,name,record):
            self.hall_of_fame.append((record,name))
            self.hall_of_fame.sort()
            file_score = open('clickeur','wb')
            pickle.dump(self.hall_of_fame,file_score)
            file_score.close()
            self.build()

    def draw(self):
        pass

high_score = high_score(101,40)
grp_button.add(high_score)

##################################################################################################
###################################New Game#######################################################
##################################################################################################

grp_blok.empty()
image_all = [blok_build((0,0,255)), blok_build((255,0,0)), blok_build((0,255,0))]

class new_game(pygame.sprite.Sprite):
        def __init__(self,image,xpos,ypos,grp_blok,matrix_blok,grp_button,spr_combo):
                pygame.sprite.Sprite.__init__(self)
                self.image = image
                self.rect = self.image.get_rect().move(xpos,ypos)
                self.grp_blok = grp_blok
                self.grp_button = grp_button
                self.matrix_blok = matrix_blok
                self.alive = True
                self.combo = spr_combo
                self.delay = 200
                self.level = 0
                
        def update(self):
                pass

        def draw(self):
                pass

        def click(self):
                self.remove(self.grp_button)
                self.grp_blok.empty()        #all blok should be deleted
                for x in range(0,10):           #and the entire matrix
                        for y in range(0,16):   #should be filled with
                                matrix_blok[x][y] = None
                self.alive = True
                self.combo.score = 0
                self.delay = 200
                self.level = 0

new_game = new_game(image_new_game,20,70,grp_blok,matrix_blok,grp_button,spr_combo)
            
###############################################################################################
##################################the main loop################################################
###############################################################################################

pivot = 0       #a line of blok that increase
old = pygame.time.get_ticks()   #last time we added a blok

spr_double.click()  # 2x scale setup


while True :
    clock.tick(24)
    for event in pygame.event.get():
        if event.type == QUIT:
            sys.exit(0)
        else:
            if event.type == MOUSEBUTTONDOWN:
                #those blok
                if new_game.alive == True:
                    for sprite_click in pygame.sprite.spritecollide (spr_mice, grp_blok, False) :
                        sprite_click.do = sprite_click.clicked    
        #compare button with mouse
        for sprite_click in pygame.sprite.spritecollide (spr_mice, grp_button, False) :
            sprite_click.click()


#those blok
    grp_blok.update()
    grp_blok.draw(screen)
    if new_game.alive == True:
        new = pygame.time.get_ticks()   #it is time to add a blok below
        if new >= old + new_game.delay :           #oh yes we can
            old = new               #save new timer value for next time
            if pivot >= 10:         #make sure we dont have already 10 blok below
                pivot = 0
            if matrix_blok[pivot][15] == None:  #make sure position below is not taken
                new_blok = spr_blok(pivot*10,150,choice(image_all),grp_blok, grp_combo)
                grp_blok.add(new_blok)      #create new blok at given position
                pivot += 1                  #increase pivot
            else:
                matrix_blok[pivot][15].do = matrix_blok[pivot][15].jump

        for x in range(0,100,10) :          #line scan
            if pivot >= 10:             #if we have 10 on 1st line
                if matrix_blok[x/10][15] != None:
                    new_blok = matrix_blok[x/10][15]
                    new_blok.do = new_blok.jump
            if matrix_blok[x/10][0] != None:    #if we have one on last line
                new_game.alive = False

        else:
            if new_game.alive == False:
                grp_button.add(new_game)
                grp_blok.empty()        #all blok should be deleted
                for x in range(0,10):           #and the entire matrix
                        for y in range(0,16):   #should be filled with
                                matrix_blok[x][y] = spr_dead(x,y,grp_blok,matrix_blok)
                high_score.new_entry('no name',spr_combo.score)
                new_game.alive = None

        if spr_combo.score >= 4000:
            if spr_combo.score >= 8000:
                if spr_combo.score >= 16000:
                    if spr_combo.score >= 24000:
                        if spr_combo.score >= 40000:
                            new_game.delay = 100
                            new_game.level = 5
                        else:
                            new_game.delay = 120
                            new_game.level = 4
                    else:
                        new_game.delay = 140
                        new_game.level = 3
                else:
                    new_game.delay = 160
                    new_game.level = 2
            else:
                new_game.delay = 180
                new_game.level = 1
        else:
            new_game.delay = 200
            new_game.level = 0
                                

#all button like scaler , score , level chooser
    grp_button.update()             #all button
    grp_button.draw(screen)
#blok that becom combo and will be drawn on top of the rest
    grp_combo.update()              #score
    grp_combo.draw(screen)
#screen update
    spr_mice.update()
    spr_mice.mouse_do(spr_mice)
    spr_mice.screen_do(screen,window)
    pygame.display.flip()
    screen.blit(background,(0,0))
