import pygame
from pygame.locals import *
import sys
import shelve
import atexit
import os.path
import glob
import pickle
import pygame.image
import pygame.font
import pygame.key
import pygame.mouse
import pygame.display
import pygame.mixer
import pygame.mixer_music
import pygame.time
import pygame.event
import pygame.mouse
import random

class Event:
        """this is a superclass for any events that might be generated by an
        object and sent to the EventManager"""
        def __init__(self):
                self.name = "Generic Event"

class TickEvent(Event):
    def __init__(self):
        self.name = 'CPU Tick Event'

class QuitEvent(Event):
    def __init__(self):
        self.name = 'Program Quit Event'

class MapBuiltEvent(Event):
    def __init__(self, map):
        self.name = 'Map Finished Building Event'
        self.map = map

class GameStartedEvent(Event):
    def __init__(self, game):
        self.name = 'Game Started Event'
        self.game = game

class CharacterSelectRequest(Event):
    def __init__(self, species, index):
        self.name = 'Character Select Request'
        self.species = species
        self.index = index

class CharacterPlaceEvent(Event):
    """
    This event occurs when a Character is *placed* in a sector, ie it doesn't
    move there from an adjacent sector.
    """
    def __init__(self, row, column, permission):
        self.name = 'Character Placement Event'
        self.column = column
        self.row = row
        self.permission = permission

class CursorMoveEvent(Event):
    def __init__(self, row, column):
        self.name = 'Cursor Placement Event'
        self.column = column
        self.row = row

class Message(Event):
        def __init__(self, string1, string2, string3, bool1, bool2):
            self.name = 'Message'
            self.s1 = string1
            self.s2 = string2
            self.s3 = string3
            self.b1 = bool1
            self.b2 = bool2

class ChangeTutorial(Event):
        def __init__ (self):
            self.name = 'Change Tutorial'

class NextTutorial(Event):
        def __init__ (self):
            self.name = 'Next Tutorial'

class ChangeTileEvent(Event):
    def __init__(self, row, column, index):
        self.name = "Change Tile Event"
        self.column = column
        self.row = row
        self.index = index


class PanelChange(Event):
    def __init__(self, types, x, y):
        self.name = 'Mouse Clicked panel change'
        self.type = types
        self.x = x
        self.y = y

        
#------------------------------------------------------------------------------
# This class manages the events that occur in the game and the notification of
# various domains of the code and game for updating. Every class has a notify
# method that recieves and sends information to the event manager that will
# then propogate the messages through the rest of the program
class EventManager:
        """this object is responsible for coordinating most communication
        between the Model, View, and Controller."""
        def __init__(self ):
                from weakref import WeakKeyDictionary
                self.listeners = WeakKeyDictionary()

        #----------------------------------------------------------------------
        def RegisterListener( self, listener ):
                self.listeners[ listener ] = 1

        #----------------------------------------------------------------------
        def UnregisterListener( self, listener ):
                if listener in self.listeners.keys():
                        del self.listeners[ listener ]

        #----------------------------------------------------------------------
        def Post( self, event ):
                for listener in self.listeners.keys():
                        #NOTE: If the weakref has died, it will be 
                        #automatically removed, so we don't have 
                        #to worry about it.
                        listener.Notify( event )


#------------------------------------------------------------------------------
# Class that takes in keyboard inputs, parses them, and outputs them to the
# event manager
class InputController:
    """..."""
    def __init__(self, evManager):
        self.evManager = evManager
        self.evManager.RegisterListener(self)
        self.x = 0
        self.y = 0
        self.locked = True
        self.tCount = 0

    #----------------------------------------------------------------------
    def Notify(self, event):
        if isinstance(event, TickEvent):
            # Handle input events.
            for event in pygame.event.get():
                print "i am notify"
                
                ev = None


                if event.type == KEYDOWN and event.key == K_ESCAPE:
                    ev = QuitEvent()
                elif (event.type == KEYDOWN and event.key == K_TAB): #skip
                    ev = ChangeTutorial()
                    self.locked = not self.locked
                elif event.type == KEYDOWN and event.key == K_SPACE and self.locked: #next
                    ev = NextTutorial()
                    self.tCount += 1
                    if self.tCount > 6:
                            self.locked = not self.locked
                elif (self.locked):
                    None
                ########## ANIMAL SELECTION ############################
                elif event.type == KEYDOWN and event.key == K_a:
                    species = "tree"
                    ev = CharacterSelectRequest(species, 0)
                elif event.type == KEYDOWN and event.key == K_q:
                    species = "banana"
                    ev = CharacterSelectRequest(species, 9)
                elif event.type == KEYDOWN and event.key == K_s:
                    species = "shrub"
                    ev = CharacterSelectRequest(species, 1)
                elif event.type == KEYDOWN and event.key == K_d:
                    species = "sheep"
                    ev = CharacterSelectRequest(species, 2)
                elif event.type == KEYDOWN and event.key == K_f:
                    species = "caribou"
                    ev = CharacterSelectRequest(species, 3)
                elif event.type == KEYDOWN and event.key == K_g:
                    species = "rabbit"
                    ev = CharacterSelectRequest(species, 4)
                elif event.type == KEYDOWN and event.key == K_h:
                    species = "bear"
                    ev = CharacterSelectRequest(species, 5)
                elif event.type == KEYDOWN and event.key == K_w:
                    species = "tiger"
                    ev = CharacterSelectRequest(species, 8)
                elif event.type == KEYDOWN and event.key == K_j:
                    species = "wolf"
                    ev = CharacterSelectRequest(species, 6)
                elif event.type == KEYDOWN and event.key == K_k:
                    species = "human"
                    ev = CharacterSelectRequest(species, 7)
                ########## CURSOR MOVEMENT ############################
                elif event.type == KEYDOWN and event.key == K_DOWN and self.y < 19:
                    self.y += 1
                    ev = CursorMoveEvent( self.x, self.y)
            
                elif event.type == KEYDOWN and event.key == K_UP and self.y > 0:
                    self.y -= 1
                    ev = CursorMoveEvent( self.x, self.y)
            
                elif event.type == KEYDOWN and event.key == K_LEFT and self.x > 0:
                    self.x -= 1
                    ev = CursorMoveEvent( self.x, self.y)
            
                elif event.type == KEYDOWN and event.key == K_RIGHT and self.x < 19:
                    self.x += 1
                    ev = CursorMoveEvent( self.x, self.y)
                    
                elif event.type == KEYDOWN and event.key == K_RETURN:
                    ev = CharacterPlaceEvent( self.x, self.y, 0)



                if event.type == pygame.MOUSEBUTTONDOWN:
                        print "mouse!"

                        pos = pygame.mouse.get_pos()
                        print pos[0]
                        print pos[1]
                        
                        if (pos[0] >= 50 and pos[0] <= 150) and (pos[1] >= 510 and pos[1] <= 550) and self.locked:
                                ev = ChangeTutorial()
                                self.locked = not self.locked

                        elif (pos[0] >= 650 and pos[0] <= 750) and (pos[1] >= 510 and pos[1] <= 550) and self.locked:
                                ev = NextTutorial()
                                self.tCount += 1
                                if self.tCount > 6:
                                    self.locked = not self.locked

                        elif (self.locked):
                            None

                        elif pos[0] >= 336 and pos[0] <= 428 and pos[1] >= 0 and pos[1] <= 73:
                            print "plant!"
                            ev = PanelChange("plants", pos[0], pos[1])

                        elif pos[0] > 428 and pos[0] <= 529 and pos[1] >= 0 and pos[1] <= 73:
                            print "herbivore"
                            ev = PanelChange("herbPanel1", pos[0], pos[1])

                        elif pos[0] > 529 and pos[0] <= 621 and pos[1] >= 0 and pos[1] <= 73:
                            print "carnivore arrggghh!"
                            ev = PanelChange("carnivore", pos[0], pos[1])

                        elif pos[0] > 621 and pos[0] <= 723 and pos[1] >= 0 and pos[1] <= 73:
                            print "omnivore or back!"
                            ev = PanelChange("omnivore", pos[0], pos[1])


                        elif pos[0] >= 475 and pos[0] < 550 and pos[1] >= 185 and pos[1] <= 225:
                            ev = CursorMoveEvent( self.x, self.y)

                if ev:
                     self.evManager.Post(ev)


#------------------------------------------------------------------------------
# Class that controlls the natural computer tick and progression of the game
class CPUSpinnerController:
    """..."""
    def __init__(self, evManager):
        self.evManager = evManager
        self.evManager.RegisterListener(self)

        self.keepGoing = 1

    #----------------------------------------------------------------------
    def Run(self):
        print "cpu!"
        while self.keepGoing:
            event = TickEvent()
            self.evManager.Post(event)

    #----------------------------------------------------------------------
    def Notify(self, event):
        if isinstance(event, QuitEvent):
            # This will stop the while loop from running.
            self.keepGoing = 0
            
###------------------------------------------------------------------------------
# Class that take in mouse inputs, parses them, and outputs them to the event
# manager
class MouseController:
    def __init__(self, evManager):
        self.evManager = evManager
        self.evManager.RegisterListener(self)

##    #----------------------------------------------------------------------
    def Notify(self, event):
        if isinstance(event, TickEvent):
            for event in pygame.event.get():
                ev = None
                if event.type == pygame.MOUSEBUTTONDOWN:
                    # User clicks the mouse. Get the position
                    print "mouse!"
                    
                    pos = pygame.mouse.get_pos()
                    print pos[0]
                    print pos[1]


                    if pos[0] >= 336 and pos[0] <= 428 and pos[1] >= 0 and pos[1] <= 73:
                        print "plant!"
                        ev = PanelChange("plants")

                    if pos[0] > 428 and pos[0] <= 529 and pos[1] >= 0 and pos[1] <= 73:
                        print "herbivore"
                        ev = PanelChange("herbPanel1")
                        
                    if pos[0] > 529 and pos[0] <= 621 and pos[1] >= 0 and pos[1] <= 73:
                        print "carnivore arrggghh!"
                        ev = PanelChange("carnivore")

                    if pos[0] > 621 and pos[0] <= 723 and pos[1] >= 0 and pos[1] <= 73:
                       print "omnivore or back!"
                       ev = PanelChange("omnivore")

                    if ev:
                        self.evManager.Post(ev)
                    

#--------------------------------------------------------------------------------------
# This Class codes for the details of each of the cells of the individual game
# board grid - this includes the terrain of the cell as well as any organism
# that is contained inside
class Cell:

    #----------------------------------------------------------------------------
    # Terrain class: will (potentially) be split into new file later 
    class Terrain:
        def __init__(self, terrain):
            self.type = terrain

        def terrainType(self):
                return self.type


    #----------------------------------------------------------------------------
    # Organism class: will (potentially) be split into new file later 
    class Organism:

        def __init__(self, organism, typ, rang, food):
            #Set the type of the organism, plant, herbivore, omnivore, etc.
            #At the moment this is limited to place holder variables 1 and 2
            self.speices = organism
            self.type = typ
            self.range = rang
            self.food = food
            self.status = 0

        def organismType(self):
            return self.type

        def organismRange(self):
                return self.range

        def organismFood(self):
                return self.food

        def organismSpecies(self):
            return self.species

        def organismStatus(self):
            return self.status

        def changeStatus(self):
            self.status = 1 - self.status

    #----------------------------------------------------------------------------
    # Initialize the cell with a terrain and an organism 
    def __init__(self):
        terrain = random.randint(1, 10)
        if 1 <= terrain <= 7:
                self.terrain = Cell.Terrain(1)
        elif 8 <= terrain <= 9:
                self.terrain = Cell.Terrain(2)
        elif terrain == 10:
                self.terrain = Cell.Terrain(3)
        self.organism = Cell.Organism("empty", 0, 0, 0)
        self.eatenRow = 0
        self.eatenCol = 0
        self.foodsources = 0
        self.foodquota = 0

    #----------------------------------------------------------------------------
    #Function that is used to update the organism contained in the cell
    def addOrganism(self, organism, typ, rang, food):
        self.organism = Cell.Organism(organism, typ, rang, food)


    #----------------------------------------------------------------------------
    # Check to see if there is an organism 
    def isFull(self):
        return (self.organism.organismType() != 0)


    #----------------------------------------------------------------------------
    # Check to see if the cells organism is currently being used
    def isUsable(self):
        return (self.organism.organismStatus() != 1)

    #----------------------------------------------------------------------------
    # Returns the amount of food (mass) a given cell gives
    def foodAmount(self):
        return self.organism.organismFood()

    #----------------------------------------------------------------------------
    # Sets the status of the given cell to eaten, so that it wont be used again
    def changeStatus(self):
        return self.organism.changeStatus()

    #----------------------------------------------------------------------------
    # Pulls up the range of the organism in the cell 
    def cellRange(self):
        return self.organism.organismRange()


    #----------------------------------------------------------------------------
    # Returns the type of organism containted in the cell 
    def cellType(self):
        return self.organism.organismType()

    #----------------------------------------------------------------------------
    # Returns the type of terrain contained in the cell
    def terrainType(self):
        return self.terrain.terrainType()

    #----------------------------------------------------------------------------
    # outputs info to the game's display about the specified cell 
    def displayInfo(self):
        ter = self.terrain.terrainType()
        ran = self.organism.organismRange()
        typ = self.organism.organismType()
        
        print("Terrain type:" + str(ter))
        if typ == 0:
            print("No organism")
        else:
            print("Organism type:" + typ)
            print("Organism range:" + str(ran))
            

#---------------------------------------------------------------------------------
# The overall class that codes for the game model - this includes the grid that
# contains the terrain and game organisms, as well as codes for the game logic
# involved in correctly placing them 
class GameBoard:
        """..."""

        #------------------------------------------------------------------
        def __init__(self, evManager, height, width):
                
    
                self.STATE_PREPARING = 0
                self.STATE_RUNNING = 1
                self.STATE_PAUSED = 2
                
                
                self.evManager = evManager
                self.evManager.RegisterListener(self)
                

                self.state = self.STATE_PREPARING
                
                self.height = height
                self.width = width

                self.grid = []
                self.output = []

                self.selectSpecies = ""
                self.selectType = ""
                self.selectRange = 0
                self.food = 0
                self.foodneeded = 0

                self.tutorial = True

        #------------------------------------------------------------------
        # Method that initializes the game upon startup - randomly generates
        # a map of different terrain types
        def start(self, height, width):
                for row in range(height):
                    self.grid.append([])
                    self.output.append([])
                    for column in range(width):
                        cell = Cell()
                        if cell.terrainType() == 2:
                                ev = ChangeTileEvent(row, column, 2)
                                self.evManager.Post(ev)
                        if cell.terrainType() == 3:
                                ev = ChangeTileEvent(row, column, 1)
                                self.evManager.Post(ev)   
                        self.grid[row].append(cell)
                self.state = self.STATE_RUNNING
                species = "tree"
                ev = CharacterSelectRequest(species, 0)
                self.evManager.Post(ev)
                ev = GameStartedEvent(self)
                self.evManager.Post(ev)

        #------------------------------------------------------------------
        def getRows(self):
                return self.width

        #------------------------------------------------------------------
        def getCols(self):
                return self.height

        #------------------------------------------------------------------
        # This method is called when the type of organism being placed changes
        # and is responsible for chanigng all relavant data memembers such that
        # the correct organism is placed in a suitable manner 
        def determineType(self, organism):
            if organism == "human":
                    self.selectRange = 4
                    self.selectType = "omnivores"
                    self.food = 4
                    self.foodneeded = 6
        ###### Carnivores
            elif organism == "wolf":
                    self.selectType = "carnivore"
                    self.selectRange = 3
                    self.food = 2
                    self.foodneeded = 3
            elif organism == "tiger":
                    self.selectType = "carnivore"
                    self.selectRange = 3
                    self.food = 3
                    self.foodneeded = 3
            elif organism == "bear":
                    self.selectType = "carnivore"
                    self.selectRange = 3
                    self.food = 3
                    self.foodneeded = 4
        ###### Herbivores
            elif organism == "sheep" or organism == "cow":
                    self.selectType = "herbivore"
                    self.selectRange = 2
                    self.food = 1.5
                    self.foodneeded = 2
            elif organism == "caribou":
                    self.selectType = "herbivore"
                    self.selectRange = 2
                    self.food = 2
                    self.foodneeded = 3
            elif organism == "rabbit":
                    self.selectType = "herbivore"
                    self.selectRange = 2
                    self.food = 1
                    self.foodneeded = 1
        ###### Plants
            elif organism == "tree":
                    self.selectType = "plant"
                    self.selectRange = 1
                    self.food = 1
                    self.foodneeded = 0
            elif organism == "shrub":
                    self.selectType = "plant"
                    self.selectRange = 1
                    self.food = 1
                    self.foodneeded = 0
            elif organism == "banana":
                    self.selectType = "plant"
                    self.selectRange = 1
                    self.food = 1
                    self.foodneeded = 0
            else:
                    self.selectRange = 0
                    self.selectType = 0

        #------------------------------------------------------------------
        # addOrganism is responsible for placing an organism in the appropriate
        # place when user input calls for it - calls helper functions found
        # below in order to use the game logic to determine if the action is
        # viable
        def addOrganism(self, row, column):
                print "in addorganism"
                if self.selectSpecies == "info":
                        self.displayInfo( row, column )
                elif self.viableAdd(row, column) == True:
                        self.grid[row][column].addOrganism(self.selectSpecies, self.selectType, self.selectRange, self.food)
                        if (self.selectSpecies == "human"):
                            print "YAY YOU WON THE GAME"
                            ev = Message("!!!YOU HAVE WON!!!",
                                 "YOU HAVE ADDED A HUMAN TO ECOVILLE",
                                 "Now he can enjoy all the plants and animals you have given him", False, False)
                            self.evManager.Post(ev)
                        return 1
                else:
                    print("Invalid organism placement")
                    return 0
                    
        #-------------------------------------------------------------------
        # helper function for viable add that checks to determine if there are
        # any elements of the game state that would preclude the placement of
        # an organism at the particular spot - food levels, terrain is already
        # occupied, unsuitable terrain, etc. 
        def viableAdd(self, row, column):
                print "hits viable add"
                if self.grid[row][column].isFull():
                    ev = Message("You cannot place that here",
                                 "There is already something in this spot!",
                                 "For more information about plants and animals check 'more info'", False, False)
                    self.evManager.Post(ev)
                    pygame.display.update()
                    return False

                terrain = self.grid[row][column].terrainType()
                if terrain == 3:
                    print "random terrain"
                    ev = Message("You cannot place organisms here",
                                 "This terrain is unsuitable for organisms",
                                 "For more information about plants and animals check 'more info'", False, False)
                    self.evManager.Post(ev)
                    pygame.display.update()
                    return False

                if self.selectType == "plant":
                    ev = Message("Congratulations, you have successfully placed a plant!",
                                     "Click another cell to place more plants", "Or click the back arrow to access more animals", False, False)
                    self.evManager.Post(ev)
                    pygame.display.update() 
                    if  terrain == 1:
                        return True
                    elif terrain == 2:
                        self.food = 2
                        return True

                foodsources = self.checkRange(row, column)
                print("FOODSOURCES: " + str(foodsources))

                if foodsources >= self.foodneeded:
 
                        self.grid[row][column].foodsources = foodsources
                        self.grid[row][column].foodquota = self.foodneeded
                        ev = Message("Congratulations, you have successfully placed an organism!",
                                     "Click another cell to place more organisms", "Or click the back arrow to access more options", False, False)
                        self.evManager.Post(ev)
                        return True
                else:
                        ev = Message("There is not enough food at this location",
                                     "Invalid organism placement", "Please check the organisms feeding area and diet", False, False)
                        self.evManager.Post(ev)
                        pygame.display.update()
                        return False


        #--------------------------------------------------------------------
        # A helper function for vaible add that checks every grid square and
        # returns the total amount of food that is found in the organisms
        # vicinity
        def checkRange( self, row, column):
                foodsources = 0
                for i in range(row - self.selectRange, row + self.selectRange + 1):
                        for j in range(column - self.selectRange, column + self.selectRange + 1):
                                if i == row and j == column:
                                        continue
                                elif i >= 0 and i<20 and j >= 0 and j < 20:
                                        k = self.grid[i][j].cellRange()
                                        l = self.selectRange -1
                                        o = self.grid[i][j].isUsable()
                                        p = self.grid[i][j].foodAmount()
                                        if  l  == k and o:
                                                self.grid[i][j].changeStatus()
                                                self.grid[i][j].eatenRow = row
                                                self.grid[i][j].eatenCol = column
                                                foodsources += p
                                        elif l == k and self.stealFood( i, j ):
                                                self.grid[i][j].eatenRow = row
                                                self.grid[i][j].eatenCol = column
                                                foodsources += p
                return foodsources

        #--------------------------------------------------------------------
        # Helper function that codes for interactions of multiple organisms
        # in relation to excess food - if one organism has too much food this
        # method allows a newly placed one to "steal" it from them if needed
        def stealFood( self, row, column):
                eaten = self.grid[row][column]
                i = eaten.eatenRow
                j = eaten.eatenCol
                eater = self.grid[i][j]
                if eater.foodsources > eater.foodquota:
                        self.grid[i][j].foodsources -= eaten.foodAmount()
                        return True

                
        #--------------------------------------------------------------------
        # Helper function that displays the info of a particular cell
        def displayInfo( self, row, column ):
                print("Cell [" + str(row) + "," + str(column) + "]")
                self.grid[row][column].displayInfo()

        #--------------------------------------------------------------------
        # This function is called when the user attempts to change the type of
        # species that they are placing, and changes the relavant data memebers
        # of game board
        def selectSpecies(self, species):
                self.species = species
                self.determineType(species)
                
        #--------------------------------------------------------------------
        # Notify method responsible for interacting and recieving input from
        # the event manager
        def Notify(self, event):
    
                if isinstance(event, TickEvent):
                        if self.state == self.STATE_PREPARING:
                                self.start(20, 20)
                                ev = MapBuiltEvent(self)
                                self.evManager.Post(ev)
                                self.state = self.STATE_RUNNING

                if isinstance(event, CharacterPlaceEvent) and (not self.tutorial):
                        if event.permission == 0:
                                if self.addOrganism( event.row, event.column ):
                                        ev = CharacterPlaceEvent(event.row, event.column, 1)
                                        self.evManager.Post(ev)
 
                if isinstance(event, CharacterSelectRequest) and (not self.tutorial):
                        print "yeah!!"
                        print event.species
                        self.determineType( event.species)
                        self.selectSpecies = event.species

                if isinstance(event, ChangeTutorial):
                        self.tutorial = not (self.tutorial)
                        pygame.display.update()
                        
                        
################################################################################################              

#------------------------------------------------------------------
# load an image with transparency (key #ff00ff)
# convert to display surface format
def makeImage(filename):
    image = pygame.image.load(filename).convert()
    image.set_colorkey((255,0,255))
    image.convert()
    return image

# load a whole set of ground tiles from a manifest file
def makeGroundTiles(filename):
    f = open(os.path.join('assets/',filename + '.tiles'))
    tiles = []
    for line in f.readlines():
        line = line.rstrip()
        if line[0] == '#':
            continue
        tiles.append(makeImage(os.path.join('gfx','tiles',line)))
    f.close()
    return tiles

#------------------------------------------------------------------
# load a whole object tile set
def makeObjectTileSet(manifest):
    tiles = []
    # read the tile definition file
    f = open(os.path.join('assets',manifest + '.obj'))
    for line in f.readlines():
        line = line.rstrip()
        if line[0] == '#':
            continue
        tiles.append(makeImage(os.path.join('gfx','objects',line)))
        print "happened once"
    f.close()
    return tiles

#------------------------------------------------------------------
def drawBackground(level, tileset, screen):
    # offset of *top-left corner* of top left tile
    # 400 - 19 (half tile width)
    # 120 - 9 (half height of top face of isometric cube)
    rowstartx = 381
    rowstarty = 111
    for i in level:
        xoff = rowstartx
        yoff = rowstarty
        rowstartx -= 18
        rowstarty += 9
        for j in i:
            screen.blit(tileset[j],(xoff,yoff))
            xoff += 18
            yoff += 9

#------------------------------------------------------------------
# render objects & mobs (non-flat tiles; can be any height, but only 1 wide)
# objects must be considered in terms of their *bottom-left corner* because of the varying heights
# the "hotspot" of a mob - the centre of its bottom face - moves in two steps:
#   - from source-tile centre to joining edge of source & dest
#   - from joining edge of source & dest to centre of dest
def drawObjectsAndMobs(level, tileset, mobs, surface, frameno, targets = None):
    ix = 0
    iy = 0

    xstart = 381
    ystart = 129
    for i in level:
        xoff = xstart - (iy * 18)
        yoff = ystart + (iy * 9)
        for j in i:
            if not j == -1:
                surface.blit(tileset[j],(xoff,yoff-tileset[j].get_height()))
            xoff += 18
            yoff += 9
            for mob in mobs:
                if mob.location[0] == ix and mob.location[1] == iy:
                    mob.draw(surface, frameno, targets)
            ix += 1
        ix = 0
        iy += 1

#------------------------------------------------------------------
# Short message to output at the end of the game
def exitFunc():
    print "Bye!"


atexit.register(exitFunc)

#------------------------------------------------------------------
# Helper functio that makes an empry array of a specified size
def makeEmptyArray(v):
    array = []
    for i in range(20):
        array2 = []
        for j in range(20):
            array2.append(v)
        array.append(array2)
        del array2
    return array


class GameBoardView:
    
    def __init__(self, screen, evManager, tileset, objectTileSet):
        self.STATE_PREPARE = 0
        self.STATE_RUN = 1
        self.state = self.STATE_PREPARE

        self.evManager = evManager
        self.evManager.RegisterListener(self)

        self.screen = screen
        self.level = []
        # background
        self.level.append(makeEmptyArray(0))
        self.level.append(makeEmptyArray(-1))
    
        # filename
        self.filename = ''
        # edit cursor position
        self.x = 0
        self.y = 0
        # tile set index & current tile set (ground, overlay, object)
        self.setIndex = 0 # selects the type of organism
        self.set = 1
        # highlighting graphics
        # selected tile type
        self.tileHighlighter = makeImage(os.path.join('gfx','current_tile.bmp'))
        # selected grid square
        self.gridHighlighter = makeImage(os.path.join('gfx','current_square.bmp'))
        # mode = map editor
        self.i = 0
        self.mode = 0
        self.tileSet = tileset

        
        self.panelType = "mainPanel"
        self.objectTileSet = makeObjectTileSet(self.panelType) 
        self.spriteTileSet = makeObjectTileSet("objects")

        # prepare board
        self.draw()
        self.panelDraw()
        self.highLighter()
        self.state = self.STATE_RUN

        # add background of trees
        tree = makeImage(os.path.join('gfx','objects',"JTree.bmp"))
        self.screen.blit(tree, (150,0))
        self.screen.blit(tree, (200,30))
        self.screen.blit(tree, (5, 5))
        self.screen.blit(tree, (40,40))
        self.screen.blit(tree, (120,60))
        self.screen.blit(tree, (-15, 100))
        self.screen.blit(tree, (80,120))
        self.screen.blit(tree, (5,150))        
        self.screen.blit(tree, (250,50))
        self.screen.blit(tree, (320,10))

        self.screen.blit(tree, (380,15))
        self.screen.blit(tree, (500,40))
        self.screen.blit(tree, (450,50))
        self.screen.blit(tree, (600,50))
        self.screen.blit(tree, (700,10))
        self.screen.blit(tree, (750,60))
        self.screen.blit(tree, (670,75))
        self.screen.blit(tree, (550,100))
        self.screen.blit(tree, (620,130))
        self.screen.blit(tree, (690,140))
        self.screen.blit(tree, (730,180))

        self.screen.blit(tree, (740,305))
        self.screen.blit(tree, (650,350))
        self.screen.blit(tree, (575,390))
        self.screen.blit(tree, (690,400))
        self.screen.blit(tree, (510,420))

        self.screen.blit(tree, (-30,230))
        self.screen.blit(tree, (40,360))
        self.screen.blit(tree, (125,390))
        self.screen.blit(tree, (10,400))
        self.screen.blit(tree, (200,430))
        

        #Messageboard drawing presets
        self.font = pygame.font.SysFont(None, 30)
        self.font2 = pygame.font.SysFont(None, 20)
        self.white = (255, 255, 255)
        self.black = (0, 0, 0)
        self.mbcolor = (146,209,79)

        #load pictures
        controls = makeImage(os.path.join('gfx','objects',"controls.jpg"))
        self.next = makeImage(os.path.join('gfx','objects',"Next.png"))
        self.skip = makeImage(os.path.join('gfx','objects',"Skip.png"))
        
        self.tutorial = True
        self.tutorialCount = 1
        
        # draw messageboard
        self.drawMessageBoard("Welcome to Chain of Life", "",
                              "To start the tutorial press next, " +
                              "to continue to the game hit skip", True, True)
        pygame.draw.rect(self.screen, self.white, [46, (self.screen.get_height()-92),
                                                   (self.screen.get_width()-96),79],4)
        self.screen.blit(controls, (250,185))
        
        

        
        


    #------------------------------------------------------------------
    # Helper function responsible for drawing the panel at the top of the game
    # view, used in teh selection of organisms and species to place
    def panelDraw(self):

        if self.set == 0:
            tiles = self.tileSet
        else:
            tiles = self.objectTileSet
        count = 0
        offset = 200 #it was 38 originally
        for tile in tiles:
            self.screen.blit(tile,(220 - ((0 - count) * offset), 0))
            count += 1

    #------------------------------------------------------------------        
    # Method that controls the highlighter that is used to indicate what is
    # currently selected by the user
    def highLighter(self):
    
        if self.setIndex == 0:
            self.i = 0 # tree

        
        if self.setIndex == 1:
            self.i = 1 # sheep
            

        if self.setIndex == 2:
            self.i = 2 # wolf

        #self.screen.blit(self.tileHighlighter, (380+self.i*(40), 1))
               
        self.screen.blit(self.gridHighlighter,(381 + (self.x*18) - (self.y*18), 111 + (self.x*9) + (self.y*9)))

    #------------------------------------------------------------------
    # Helper function used to create message boards at the bottom of the screen,
    # used for notifications and the tutorial
    def drawMessageBoard(self, string1, string2, string3, b1, b2):
        #draw background rectangle
        pygame.draw.rect(self.screen, self.mbcolor, [50, (self.screen.get_height()-90),
                                                (self.screen.get_width()-100),75])
        #draw buttons
        if (b1):
                pygame.draw.ellipse(self.screen, self.white, [46, (self.screen.get_height()-90),
                                                100,40])
                self.screen.blit(self.skip, (38, (self.screen.get_height()-90)))
        if (b2):
                pygame.draw.ellipse(self.screen, self.white, [(self.screen.get_width()-150),
                                                (self.screen.get_height()-90),100,40])
                self.screen.blit(self.next, ((self.screen.get_width()-150),(self.screen.get_height() - 91)))
                
        #draw messgae
        self.screen.blit(self.font.render(string1, 1, self.black),
                         ((self.screen.get_width()/2 - 5*len(string1)),(self.screen.get_height() - 85)))
        self.screen.blit(self.font.render(string2, 1, self.black),
                         ((self.screen.get_width()/2 - 5*len(string2)),(self.screen.get_height() - 65)))
        self.screen.blit(self.font.render(string3, 1, self.black),
                         ((self.screen.get_width()/2 - 5*len(string3)),(self.screen.get_height() - 45)))

    def draw(self):
    
        drawBackground(self.level[0], self.tileSet, self.screen)
        drawObjectsAndMobs(self.level[1], self.spriteTileSet, [], self.screen, 0)

    def addOrganism(self):
            self.level[self.set][self.y][self.x] = self.setIndex

    def changeTile(self, row, column):
            self.level[0][column][row] = self.setIndex

    def contTutorial(self):
    
            self.tutorialCount += 1
            x = self.tutorialCount
            if x < 1:
                self.drawMessageBoard("Welcome to Chain of Life", "",
                    "To start the tutorial press next, " +
                    "to continue to the game hit skip", True, True)
            elif x == 2:
                self.drawMessageBoard("This is Ecoville, your personal eco-reserve",
                    "              Currently, there is little life in Ecoville",
                    "Your goal is to develop your reserve by adding " +
                    "plants and animals",
                    False, True)              
            elif x ==3:
                self.screen.blit(makeImage(os.path.join('gfx','objects',"range.png")), (250,185))
                self.drawMessageBoard("To add a plant or animal you must select a type",
                    "You can choose a type from the panel at the top",
                    "First select a type (i.e. plant) and an organism (i.e. shrubbery)", False, True)
            elif x == 4:
                self.drawMessageBoard("Not all organisms can be supported in Ecoville",
                    "Ecoville needs organisms native to the jungle",
                    "Check 'more information' to see each animal's environment", False, True)
            elif x == 5:
                self.drawMessageBoard("To win a level you must add an omnivore",
                    "To add an organism, it needs enough food",
                    "For instance, a spotted deer needs two banana trees one cell away", False, True)
            elif x == 6:
                self.drawMessageBoard("Now it's time to start building Ecoville",
                    "Begin by adding plants and eventually a human",
                    "Make sure to check the soil type before adding plants", False, True)
            elif x == 7:
                self.drawMessageBoard("Start off by adding a plant",
                     "Use the keyboard keys to move along the map","Hit enter to place a plant",False,True)
            elif x == 8:
                self.drawMessageBoard("Add a plant to Ecoville",
                     "Check the soil type to make sure it can support the plant type",
                     "It needs the correct amount of water, sunlight, and temperature", False, False)
                self.evManager.Post(ChangeTutorial())
                self.evManager.Post(CursorMoveEvent(0, 0))
                

            elif x == 9:
                self.drawMessageBoard("Well done, you now have a plant!",
                    "Now add an herbivore",
                    "Remember to have enough food within its feeding area", False, False)
                self.evManager.Post(ChangeTutorial())
                           
            pygame.display.update()

    #------------------------------------------------------------------
    # Method used to bring up more information about the currently selected
    # organism for use by the user in reference
    def moreInfoPanel(self, oType, number):
            if oType == "plants":
                    if number == 1:
                            self.moreInfoDraw(1, "Fruit Tree","Tree that grows in all climates",
                                              "any free cell")
                    elif number == 2:
                            self.moreInfoDraw(2, "Shrub","Plant with stems, leaves, and roots",
                                              "any free cell")
                    elif number == 3:
                            self.moreInfoDraw(3, "Banana Plant","Tropical plant found in Southern Asia",
                                              "any free cell")
            elif oType == "herbPanel1":
                    if number == 1:
                            self.moreInfoDraw(4, "Deer","Lives in all climates",
                                              "3 or more plants, provides 2 food")
                    elif number == 2:
                            self.moreInfoDraw(5, "Sheep","Typically kept as livestock in most climates",
                                              "2 or more plants, provides 1.5 food")
                    elif number == 3:
                            self.moreInfoDraw(6, "Rabbit","Live in woods, forests, and deserts",
                                              "1 plant, provides 1 food")
            elif oType == "carnivore":
                    if number == 1:
                            self.moreInfoDraw(7, "Bear","Large carnivore that eats almost anything",
                                              "4 food (ie 4 rabbits or 2 deer)")
                    elif number == 2:
                            self.moreInfoDraw(8, "Wolf","Largest member of the dog family",
                                              "3 food (ie 3 rabbits or 2 deer)")
                    elif number == 3:
                            self.moreInfoDraw(9, "Tiger","Largest cat species",
                                              "4 food (ie 4 rabbits or 2 deer)")
            elif oType == "omnivore":
                    if number == 1:
                            self.moreInfoDraw(9, "Human","Your avatar in the game world!",
                                              "6 food(ie a bear and a deer)")
            

            pygame.display.update()

    #------------------------------------------------------------------
    # Helper function used to output more information to the screen when necessary
    def moreInfoDraw (self, num, s1, s2, s3):
             pygame.draw.rect(self.screen, self.mbcolor, [250, 185,
                                        300,210])
             pygame.draw.ellipse(self.screen, self.white, [475, 185, 75, 40])
             self.screen.blit(self.font2.render("Close", 1, self.black),(490,200))

             ##add picture
             
             self.screen.blit(self.font.render(s1, 1, self.black),
                         ((402 - 5.5*len(s1)),200))
             self.screen.blit(self.font.render("Discription: ", 1, self.black),
                         (252,295))       
             self.screen.blit(self.font2.render(s2, 1, self.black),
                         (255,320))
             self.screen.blit(self.font.render("Place in Range of: ", 1, self.black),
                         (252,350))
             self.screen.blit(self.font2.render(s3, 1, self.black),
                         (255,375))

    #------------------------------------------------------------------
    # Method used to interact and reciev input from the event manager
    def Notify(self, event):

            #----DID NOT SEEM TO DO ANYTHING----#
##            if isinstance(event, TickEvent):
##                    if self.state == self.STATE_PREPARE:
##                        self.draw()
##                        self.panelDraw()
##                        self.highLighter()
##                        pygame.display.flip()
##                        self.state = self.STATE_RUN

            if isinstance(event, CharacterPlaceEvent) and (not self.tutorial):
                    if event.permission == 1:
                        self.addOrganism()
                        self.draw()
                        pygame.display.update()

            if isinstance(event, CursorMoveEvent) and (not self.tutorial):
                    self.x = event.row
                    self.y = event.column
                    self.draw()
                    self.highLighter()
                    self.drawMessageBoard("", "", "", False, False)
                    pygame.display.update()

            if isinstance(event, CharacterSelectRequest):
                    self.setIndex = event.index
                    self.draw()
                    self.panelDraw()
                    self.highLighter()

            if isinstance(event, Message):
                    self.drawMessageBoard(event.s1, event.s2, event.s3, event.b1, event.b2)

            if isinstance(event, ChangeTutorial):
                    self.tutorial = not (self.tutorial)
                    self.drawMessageBoard("Start off by adding a plant",
                                          "Use the keyboard keys to move along the map","Hit enter to place a plant",False,False)
                    pygame.display.update()

            if isinstance(event, NextTutorial):
                    if self.tutorial == True:
                        self.contTutorial()

            if isinstance(event, ChangeTileEvent):
                    self.setIndex = event.index
                    self.changeTile(event.row, event.column)
                    self.panelDraw()
                    self.highLighter()
                    pygame.display.update()

            if isinstance(event, PanelChange):
    
                    if self.panelType == "mainPanel":
                            self.panelType = event.type
                            self.objectTileSet = makeObjectTileSet(self.panelType)
                            print "panel changed!"
                            self.draw()
                            self.panelDraw()
                   
                    elif self.panelType == "carnivore":
                            
                            if event.y > 0 and event.y < 55:
                                
                                if event.type == "plants":
                                                ev = CharacterSelectRequest("bear", 5) # bear 
                                                self.evManager.Post(ev)


                                if event.type == "herbPanel1":
                                                ev = CharacterSelectRequest("wolf", 6) # wolf
                                                self.evManager.Post(ev)

                                if event.type == "carnivore":
                                                ev = CharacterSelectRequest("tiger", 8) # tiger
                                                self.evManager.Post(ev)

                                if event.type == "omnivore":
                                                    self.panelType = "mainPanel"
                                                    self.objectTileSet = makeObjectTileSet(self.panelType)
                                                    print "panel changed!"
                                                    self.draw()
                                                    self.panelDraw()
        
                                
                            elif event.y >= 55 and event.y < 73:
                                print "info time!"
                                self.moreInfoPanel(self.panelType, (event.x-235)/100)                                
    
    
                          
                    elif self.panelType == "plants":
    
                        if event.y > 0 and event.y < 55:

                           if event.type == "plants":
                               ev = CharacterSelectRequest("tree", 0) # tree 
                               self.evManager.Post(ev)
                           if event.type == "herbPanel1":
                               ev = CharacterSelectRequest("shrub", 1) # shrub
                               self.evManager.Post(ev)
                           if event.type == "carnivore":
                               ev = CharacterSelectRequest("banana", 9) # banana
                               self.evManager.Post(ev)
                           if event.type == "omnivore":
                               self.panelType = "mainPanel"
                               self.objectTileSet = makeObjectTileSet(self.panelType)
                               print "panel changed!"
                               self.draw()
                               self.panelDraw()
                               pygame.display.update()

                        elif event.y >= 55 and event.y < 73:
                               print "info time!"
                               self.moreInfoPanel(self.panelType, (event.x-235)/100)
                           

                    elif self.panelType == "herbPanel1":
    
                        if event.y > 0 and event.y < 55:
                        
                           if event.type == "plants":
                               ev = CharacterSelectRequest("caribou", 3) # caribou
                               self.evManager.Post(ev)
                           if event.type == "herbPanel1":
                               ev = CharacterSelectRequest("sheep", 2) # sheep
                               self.evManager.Post(ev)
                           if event.type == "carnivore":
                               ev = CharacterSelectRequest("rabbit", 4) # rabbit
                               self.evManager.Post(ev)
                           if event.type == "omnivore":
                               self.panelType = "mainPanel"
                               self.objectTileSet = makeObjectTileSet(self.panelType)
                               print "panel changed!"
                               self.draw()
                               self.panelDraw()
                               pygame.display.update()

                        elif event.y >= 55 and event.y < 73:
                               print "info time!"
                               self.moreInfoPanel(self.panelType, (event.x-235)/100)


                    elif self.panelType == "omnivore":
    
                        if event.y > 0 and event.y < 55:
                  
    
                             if event.type == "plants":
                                 ev = CharacterSelectRequest("human", 7) # human
                                 self.evManager.Post(ev)
                             
                             if event.type == "omnivore":
                                 self.panelType = "mainPanel"
                                 self.objectTileSet = makeObjectTileSet(self.panelType)
                                 print "panel changed!"
                                 self.draw()
                                 self.panelDraw()
                                 pygame.display.update()
                            
                        elif event.y >= 55 and event.y < 73:
                                 print "info time!"
                                 self.moreInfoPanel(self.panelType, (event.x-235)/100)

                    pygame.display.update()
                           

                               
################################################################################################                                                                                                                  

def main():
    
    # Initialize pygame
    pygame.init()
    
    """..."""
    evManager = EventManager()
    #gameBoard = GameBoard(event, 20,20) 
    pygame.display.init()
    #screen = pygame.display.set_mode((800, 600), FULLSCREEN)
    screen = pygame.display.set_mode((800, 600), HWSURFACE)
    
    pygame.font.init()
    font = pygame.font.SysFont("None", 48)
    # load ground tiles
    tileset = makeGroundTiles('ground')

    # load objects
    objectTileset = makeObjectTileSet('mainPanel')

    # hide the pointer
    pygame.mouse.set_visible(True)
    #mouse = MouseController(evManager)
    input1 = InputController(evManager)
    spinner = CPUSpinnerController(evManager)

    # splash screen
    splash = True
    pygame.event.get()
    
    screen.blit((makeImage(os.path.join('gfx','objects',"splash.jpg"))), (0,0))
    pygame.display.update()
    while (splash):
           for event in pygame.event.get():
                   if (event.type == MOUSEBUTTONUP):
                           splash = False
                           
    screen.fill((155,187,88))
    
    #print "vijay"
    board = GameBoard(evManager, 200, 200)
    view = GameBoardView(screen, evManager, tileset, objectTileset)
    
    spinner.Run()

if __name__ == '__main__':
    main()
