import pygame
from pygame.locals import *
from random import *
from Video import Video
from Civ import Civ
from Wave import Wave
from Bulle import Bulle

class Map(object): 
    def __init__(self,width,height,video,humans,stadeMax,statusMax,pStade,pStatus,pDemography): 
        self.width = int(width)
        self.height = int(height)
        self.year = 0
        self.video = video
        self.tiles = self.getBlankMap(1)
        self.units = self.getBlankMap()
        self.humans = humans
        self.pDemography = pDemography
        self.civ = Civ(self,stadeMax,statusMax,pStade,pStatus)
        self.wave = None
        self.force = 0
        self.bulles = []
        print("Mapping "+str(len(self.tiles))+" elements...")
        while True :
            self.reset()
            self.generateMap()
            if(self.generateUnits(self.humans)): break

        self.tilesIndex = ["Grass","Water","Trees","Rock"]
        self.unitsIndex = ["Blank","House","Dino","Piranha","Insects","Corpse"]
        
        self.video.setMap(self)
        print("Map OK")

    def getBlankMap(self,defaultValue=0):
        tab = []
        for h in range(0,self.width*self.height): tab.append(defaultValue)
        return tab

    def generateUnits(self,maxH):
        #Génération des unités
        for i in range (0,maxH):
            while self.placeUnit(randint(0,self.width-1),randint(0,self.height-1),1,1,0,8,20,0,0,0,0,0)==False:
                if(self.grassLeft()<10): return False
        return True

    def getPop(self):
        #Population actuelle
        totalPop = 0
        for i in self.units :
            if(i==1): totalPop += 1
        return totalPop

    def grassLeft(self):
        #Retourne le nombre d'herbe restante
        s = 0
        for t in range(0,self.width*self.height):
            if(self.tiles[t]==0): s += 1
        return s

    def reset(self):
        for y in range(0,self.height):
            for x in range(0,self.width):
                self.tiles[x+y*self.width]=1
                self.units[x+y*self.width]=0
        
    def generateMap(self):
        #Placer l'herbe (très grandes étendues)
        rr = randint(5,15)
        for i in range(1,rr):
            x = randint(0,self.width)
            y = randint(0,self.height)
            r = randint(5,10)
            self.terrainFullCircle(x,y,r,0)
        #Placer la roche (petites étendues)
        rr = randint(0,30)
        for i in range(1,rr):
            x = randint(0,self.width)
            y = randint(0,self.height)
            r = randint(1,3)
            self.terrainCircle(x,y,r,3)
        #Placer la végétation (étendues moyennes)
        rr = randint(1,7)
        for i in range(1,rr):
            x = randint(0,self.width)
            y = randint(0,self.height)
            r = randint(3,6)
            self.terrainFullCircle(x,y,r,2)
        print("Terrain OK")

    def terrainFullCircle(self,x_centre,y_centre,r,e):
        for rr in range(0,r):
            self.terrainCircle(x_centre,y_centre,rr,e)

    def terrainCircle(self,x_centre,y_centre,r,e):
        #if(x_centre<0 or y_centre<0 or x_centre>=width or y_centre>=height): return
        x=0
        y=r
        d=r-1
        while y>=x :
            self.setTile( x_centre + x , y_centre + y , e)
            self.setTile( x_centre + y , y_centre + x , e)
            self.setTile( x_centre - x , y_centre + y , e)
            self.setTile( x_centre - y , y_centre + x , e)
            self.setTile( x_centre + x , y_centre - y , e)
            self.setTile( x_centre + y , y_centre - x , e)
            self.setTile( x_centre - x , y_centre - y , e)
            self.setTile( x_centre - y , y_centre - x , e)
            if(d>=2*x):
                d = d-2*x-1
                x = x+1
            elif(d< 2*(r-y)):
                d = d+2*y-1
                y = y-1     
            else:
                d = d+2*(y-x-1)
                y = y-1
                x = x+1

    def setTile(self,x,y,e):
        if(x<0 or y<0 or x>=self.width or y>=self.height): return
        if(e==3 and self.tiles[x+y*self.width]==1): return
        else: self.tiles[x+y*self.width] = e

    def proba(self,maxi):
        if(maxi==0): return False
        if(maxi==1): return True
        return randint(1,maxi)==1

    def placeUnit(self,x,y,unit,pGrass,pWater,pTrees,pRock,pOverHuman,pOverDino,pOverPiranha,pOverInsects,pOverCorpse,toNext=False):
        #Place une unité si possible
        if(x<0 or x>=self.width or y<0 or y>=self.height): return False

        if(toNext):
            dTiles = self.nextTiles
            dUnits = self.nextUnits
        else:
            dTiles = self.tiles
            dUnits = self.units
        
        if(self.tiles[x+y*self.width]==0 and self.proba(pGrass)==False): return False
        if(self.tiles[x+y*self.width]==1 and self.proba(pWater)==False): return False
        if(self.tiles[x+y*self.width]==2 and self.proba(pTrees)==False): return False
        if(self.tiles[x+y*self.width]==3 and self.proba(pRock)==False): return False
        
        if(self.units[x+y*self.width]==1 and self.proba(pOverHuman)==False): return False
        if(self.units[x+y*self.width]==2 and self.proba(pOverDino)==False): return False
        if(self.units[x+y*self.width]==3 and self.proba(pOverPiranha)==False): return False
        if(self.units[x+y*self.width]==4 and self.proba(pOverInsects)==False): return False
        if(self.units[x+y*self.width]==5 and self.proba(pOverCorpse)==False): return False

        if(self.units[x+y*self.width]==1 and unit!=1): #Une maison meurt donne une tombe
            dUnits[x+y*self.width] = 5
            self.addBulle(x,y,1)
        else:
            dUnits[x+y*self.width] = unit
        return True

    def placeUnits(self,unit):
        #Place les monstres aléatoirement
        if(unit==2): #Dino
            self.placeUnit(randint(0,self.width-1),randint(0,self.height-1),unit,2,0,1,20,0,0,1,0,1)
        if(unit==3): #Piranha
            addPiranha = 5 #Nombre moyen de piranha ajoutés par tour
            for i in range(0,addPiranha):
                self.placeUnit(randint(0,self.width-1),randint(0,self.height-1),unit,0,0,1,0,0,0,0,0,0)
        if(unit==4): #Insects
            if(randint(1,8)==1): self.placeUnit(randint(0,self.width-1),randint(0,self.height-1),unit,1,0,1,1,0,0,1,0,0)

    def autoUnits(self):
        #Units evolutions from current to next
        self.nextTiles = self.getBlankMap()
        for k,v in enumerate(self.tiles):
            self.nextTiles[k] = self.tiles[k]
        self.nextUnits = self.getBlankMap()
        for k,v in enumerate(self.units) :
            #self.nextTiles[k] = self.tiles[k]
            #Gestion des priorités
            if(self.units[k]==0 and self.nextUnits[k]>0): continue 
            if(self.units[k]==1 and self.nextUnits[k]>1): continue #La maison est morte
            #if(self.units[k]==2 and self.nextUnits[k]==0): continue #Le dino s'est déplacé
            if(self.units[k]==3 and self.nextUnits[k]==2): continue #Le piranha est devenu Dino
            #if(self.units[k]==4 and self.nextUnits[k]>1): continue #
            if(self.units[k]==5 and self.nextUnits[k]<5 and self.nextUnits[k]>0): continue #Le corpse / Tombe est devenu autre chose (mais pas du vide)
            
            if(self.units[k]>0):
                self.nextUnits[k] = self.units[k]
            if(self.units[k]==1): #Auto expand humans
                if(randint(1,self.pDemography)==1): self.placeUnit(k%self.width-1,int(k/self.width),self.units[k],1,0,8,20,0,0,0,0,2,True)
                if(randint(1,self.pDemography)==1): self.placeUnit(k%self.width+1,int(k/self.width),self.units[k],1,0,8,20,0,0,0,0,2,True)
                if(randint(1,self.pDemography)==1): self.placeUnit(k%self.width,int(k/self.width)-1,self.units[k],1,0,8,20,0,0,0,0,2,True)
                if(randint(1,self.pDemography)==1): self.placeUnit(k%self.width,int(k/self.width)+1,self.units[k],1,0,8,20,0,0,0,0,2,True)
            if(self.units[k]==2): #Auto expand Dino
                moveDino = False
                dinoExpand = 1
                if(randint(1,dinoExpand)==1):
                    randy = randint(1,4)
                    if(randy==1): moveDino = self.placeUnit(k%self.width-1,int(k/self.width)-1,self.units[k],1,0,1,1,1,0,1,0,4,True)
                    if(randy==2): moveDino = self.placeUnit(k%self.width-1,int(k/self.width)+1,self.units[k],1,0,1,1,1,0,1,0,4,True)
                    if(randy==3): moveDino = self.placeUnit(k%self.width+1,int(k/self.width)-1,self.units[k],1,0,1,1,1,0,1,0,4,True)
                    if(randy==4): moveDino = self.placeUnit(k%self.width+1,int(k/self.width)+1,self.units[k],1,0,1,1,1,0,1,0,4,True)
                if(moveDino): self.nextUnits[k] = 0
            if(self.units[k]==3): #Auto expand Piranha
                piranhaExpand = 20
                if(randint(1,piranhaExpand)==1): self.placeUnit(k%self.width-1,int(k/self.width),self.units[k],1,0,1,0,1,0,0,0,2,True)
                if(randint(1,piranhaExpand)==1): self.placeUnit(k%self.width+1,int(k/self.width),self.units[k],1,0,1,0,1,0,0,0,2,True)
                if(randint(1,piranhaExpand)==1): self.placeUnit(k%self.width,int(k/self.width)-1,self.units[k],1,0,1,0,1,0,0,0,2,True)
                if(randint(1,piranhaExpand)==1): self.placeUnit(k%self.width,int(k/self.width)+1,self.units[k],1,0,1,0,1,0,0,0,2,True)
                if(randint(1,piranhaExpand)==1): self.placeUnit(k%self.width-1,int(k/self.width),self.units[k],1,0,1,0,1,0,0,0,2,True)
                if(randint(1,piranhaExpand)==1): self.placeUnit(k%self.width+1,int(k/self.width),self.units[k],1,0,1,0,1,0,0,0,2,True)
                if(randint(1,piranhaExpand)==1): self.placeUnit(k%self.width,int(k/self.width)-1,self.units[k],1,0,1,0,1,0,0,0,2,True)
                if(randint(1,piranhaExpand)==1): self.placeUnit(k%self.width,int(k/self.width)+1,self.units[k],1,0,1,0,1,0,0,0,2,True)
            if(self.units[k]==4): #Auto expand Insects
                insectsExpand = 1
                if(randint(1,insectsExpand)==1): self.placeUnit(k%self.width-1,int(k/self.width),self.units[k],1,0,1,1,2,0,0,0,2,True)
                if(randint(1,insectsExpand)==1): self.placeUnit(k%self.width+1,int(k/self.width),self.units[k],1,0,1,1,2,0,0,0,2,True)
                if(randint(1,insectsExpand)==1): self.placeUnit(k%self.width,int(k/self.width)-1,self.units[k],1,0,1,1,2,0,0,0,2,True)
                if(randint(1,insectsExpand)==1): self.placeUnit(k%self.width,int(k/self.width)+1,self.units[k],1,0,1,1,2,0,0,0,2,True)
                self.nextUnits[k] = 0
            #if(self.units[k]==5): #Auto expand Corpse / Tomb
        self.tiles = self.nextTiles
        self.units = self.nextUnits
    
    def nextYear(self):
        #Auto evolutions
        self.autoUnits()
        if(True):
            self.placeUnits(2)
            self.placeUnits(3)
            self.placeUnits(4)
        else:
            #self.units[int(self.width/2)+int(self.height/2)*self.width] = 4 #Insectes de test
            print("")
        self.civ.evolve()
        self.year += 1
        #print("Coming to year "+str(self.year))
        #Vérifier si défaite
        if(self.victory()): return 1
        #Vérifier si victoire
        if(self.defeat()): return 2
        return 0

    def nextMonth(self):
        return self.waving()

    def victory(self):
        if(self.year>=100 and self.civ.isGood()): return True
        return False

    def defeat(self):
        if(self.civ.isBad()): return True
        if(self.year>=100 and self.civ.isGood()==False): return True
        for i in self.units :
            if(i==1): return False
        return True

    def earthquake(self):
        self.wave = Wave(self,self.force)

    def waving(self):
        if(self.wave!=None):
            if(self.wave.progress()==True):
                self.civ.unEvolve(self.wave.force)
                self.wave = None
            return True
        return False

    def waveEffect(self,x,y):
        #Applique l'effet de la Wave
        if(x<0 or y<0 or x>=self.width or y>=self.height): return
        if(self.units[x+y*self.width]==1): #House
            if(randint(1,100)<=self.wave.force):
                if(randint(1,2)==1):
                    if(randint(1,10)>3): self.units[x+y*self.width] = 5
                    else: self.units[x+y*self.width] = 0
                    self.addBulle(x,y,2)
        if(self.units[x+y*self.width]==2): #Dino
            if(self.wave.force>90): self.units[x+y*self.width] = 0
        if(self.units[x+y*self.width]==3): #Piranha
            if(self.wave.force>45): self.units[x+y*self.width] = 0
        if(self.units[x+y*self.width]==4): #Insects
            if(self.wave.force>10): self.units[x+y*self.width] = 0
        if(self.units[x+y*self.width]==5): #Corpse
            if(self.wave.force>90): self.units[x+y*self.width] = 0

    def addBulle(self,x,y,expr):
        self.bulles.append(Bulle(x,y,expr,self.video))

