from Tkinter import *
import time
from nekobmaps import bitmaps

_AWAKE = 0
_SLEEP1 = 1
_SLEEP2 = 2
_TIMER_STEP = 400

class Text_Widget:
	
	def __init__(self, width=40,height=26):
		
		self.width = width
		self.height= height
		self.index = 1.0
		self.comm_index=1.0
		self.header="from neko import *\n"	
		self.text = Text(width=self.width, height=self.height,background='white') 

		self.scroll=Scrollbar(command=self.text.yview)
		self.text.configure(yscrollcommand=self.scroll.set,font=('Verdana',10),borderwidth=2,relief=RIDGE,foreground='blue')
		
		
	def get_command(self):
		
		self.command=self.text.get(1.0,END)
		self.temp_file=open('temp.py','w')
		self.command=self.header+self.command
		self.temp_file.write(self.command)
		self.temp_file.close()
				
	
	def clear(self):
		self.text.delete(self.index,END)
		
		
			

class Prompt:
	
	def __init__(self, width=40,height=2):
		
		self.width = width
		self.height= height
		self.index = 0
		self.comm_list={}
		self.comm_index=0
		self.prompt=">> "
		
		self.text = Text(width=self.width, height=self.height,background='white',borderwidth=2,relief=RIDGE,font=('Verdana',10),foreground='black') 

			
	def get_command(self):
		
		self.command=self.text.get(1.3,END)
		self.text.delete(1.3,END)
		self.comm_list[self.index]=self.command
		self.index=self.index+1
		self.comm_index=self.index-1
				
	
	
	def get_prev_command(self,event):
		
		try:
			self.prevcommand=self.comm_list[self.comm_index]
			self.comm_index=self.comm_index-1
		except:
			self.comm_index=self.comm_index+1
			self.prevcommand=''
			
		if self.prevcommand!='':
			
			self.text.delete(1.3,END)
			self.text.insert(1.3,self.prevcommand)
	
	def get_next_command(self,event):
		
		try:
			self.prevcommand=self.comm_list[self.comm_index]
			print self.prevcommand
			self.comm_index=self.comm_index+1
		except:
			self.comm_index=self.comm_index-1
			self.prevcommand=''
			
		if self.prevcommand!='':
			
			self.text.delete(1.3,END)
			self.text.insert(1.3,self.prevcommand)
			
			

class Grid:

    """ A Grid is a 2D array of `cells'. """
    
    def __init__(self, width=400, height=312, cells_x=8, cells_y=8,
                 background='white'):
        self.walls = {}
        self.width = width
        self.height = height
        self.cells_x = cells_x
        self.cells_y = cells_y
        self.cell_width = self.width / self.cells_x
        self.cell_height = self.height / self.cells_y
        self.background = background
        self.canvas = Canvas(width=self.width, height=self.height,
                             background=self.background,borderwidth=2,relief=RIDGE)
        self.canvas.pack(side='right')
	
	
	self.text=Text_Widget()
	self.prompt=Prompt()
	self.prompt.text.bind('<KeyRelease-Return>',self.execute)
	self.prompt.text.bind('<KeyPress-Up>',self.prompt.get_prev_command)
	self.prompt.text.bind('<KeyPress-Down>',self.prompt.get_next_command)
	self.text.text.bind('<KeyRelease-Alt_L>',self.run_code)
        
	mBar = Frame(relief=RIDGE, borderwidth=2)
	mBar.pack(fill=X)
 	FileBtn = Menubutton(mBar, text='File', underline=0)
        FileBtn.menu = Menu(FileBtn)
	FileBtn.menu.add_command(label="Clear",command=self.text.clear)
	FileBtn.menu.add_command(label="Run",command=self.menu_execute)
	FileBtn.menu.add_command(label='Quit',underline=0,command=FileBtn.quit)
	FileBtn.pack(side=LEFT, padx="2m")
	FileBtn['menu'] = FileBtn.menu
	HelpBtn = Menubutton(mBar, text='Help', underline=0)
        HelpBtn.menu = Menu(HelpBtn)
	HelpBtn.menu.add_command(label="Contents")
	HelpBtn.menu.add_command(label='Tutorial')
	HelpBtn.pack(side=LEFT, padx="2m")
	HelpBtn['menu'] = HelpBtn.menu
	mBar.tk_menuBar(FileBtn,HelpBtn)
	self.text.text.pack()
	self.prompt.text.pack(side='bottom')
	self.prompt.text.insert(1.0,self.prompt.prompt)
	
	# Draw the grid.

        x1 = 0
        t = self.width/self.cells_x
        while x1 < self.width:
            self.canvas.create_line(x1, 0, x1, self.height-1, 
                                    stipple="gray50")
            x1 = x1 + t
        
        y1 = 0
        t = self.height/self.cells_y
        while y1 < self.height:
            self.canvas.create_line(0, y1, self.width-1, y1, 
                                    stipple="gray50")
            y1 = y1 + t

        # And put a cat and mouse in it!

        self.neko = Neko(self)
        self.mouse = Mouse(self)
    
    
    def execute(self,event):
	    neko=self.neko
	    mouse=self.mouse
	    self.prompt.get_command()
	    eval(self.prompt.command)
    
    
    def run_code(self, event):
	    neko=self.neko
	    mouse=self.mouse
	    self.text.get_command()
	    execfile("temp.py")
	    
    def menu_execute(self):
	    self.run_code(1)
	    	
		
    def make_wall_coords(self, r, c, direction):
        coords = ()
        if r >= self.cells_y:
            return coords
        if c >= self.cells_x:
            return coords
        x1 = self.cell_width * c
        y1 = self.cell_height * r
        if direction == 'up':
            x2 = x1 + self.cell_width
            y2 = y1
            coords = (x1, y1, x2, y2)
        elif direction == 'left':
            x2 = x1
            y2 = y1 + self.cell_height
            coords = (x1, y1, x2, y2)
        elif direction == 'down':
            y1 = y1 + self.cell_height
            x2 = x1 + self.cell_width
            y2 = y1
            coords = (x1, y1, x2, y2)
        elif direction == 'right':
            x1 = x1 + self.cell_width
            x2 = x1
            y2 = y1 + self.cell_height
            coords = (x1, y1, x2, y2)

        return coords

    def build_wall(self, r, c, direction):
        coords = self.make_wall_coords(r, c, direction)
        if coords == ():
            return 'unable to build wall'
        x1, y1, x2, y2 = coords
        id = self.canvas.create_line(x1, y1, x2, y2, fill='red')
        self.walls[coords] = id

    def destroy_wall(self, r, c, direction):
        coords = self.make_wall_coords(r, c, direction)
        if coords == ():
            return 'unable to destroy wall'
        if not self.walls.has_key(coords):
            return 'unable to destroy wall'
        self.canvas.delete(self.walls[coords])
        del self.walls[coords]

    def wall_present(self, r, c, direction):
        coords = self.make_wall_coords(r, c, direction)
        if coords == ():
            return 0
        if self.walls.has_key(coords):
            return 1
        return 0

class NekoImages:

    """ NekoImages holds Neko Bitmap images as attributes. """

    def __init__(self, c='blue'):
        for  name in bitmaps.keys():
            img = BitmapImage(data=bitmaps[name], foreground=c)
            setattr(self, name, img)
        

class Neko:

    def __init__(self, grid, colour='blue'):
        self.state = _AWAKE
        self.awake_time = 0
        self.row = 0
        self.col = 0
        self.x = (grid.cell_width/2) 
        self.y = (grid.cell_height/2)
        self.step_x = grid.cell_width/5
        self.step_y = grid.cell_height/3
        self.images = NekoImages()
        grid.canvas.create_image(self.x, self.y, 
                                 image=self.images.awake, tags='neko')
        grid.canvas.pack()
        self.grid = grid

    def __move(self, change_x, change_y, 
               change_row, change_col, not_finished, check, imgs):
        if (check()):
            return 0
        if (self.state != _AWAKE):
            return 0
        self.grid.canvas.delete('neko')
        i = 0
        while not_finished(self.x, self.y):
            self.grid.canvas.create_image(self.x, self.y,
                                          image=imgs[i],
                                          tags='neko')
            self.grid.canvas.update()
            time.sleep(.1)
            self.grid.canvas.delete('neko')
            self.grid.canvas.update()
            self.x = change_x(self.x)
            self.y = change_y(self.y)
            i = (i + 1) % 2
        self.row = change_row(self.row)
        self.col = change_col(self.col)
        if self.grid.mouse.mouse_pos() == (self.row, self.col):
            self.grid.mouse.kill_mouse()
        self.grid.canvas.create_image(self.x, self.y,
                                      image=self.images.awake, 
                                      tags='neko')
        self.grid.canvas.update()
        self.state = _AWAKE
        return 1

    def right(self):
        r = self.row; c = self.col
        new_x = self.x + self.grid.cell_width
        return self.__move(lambda x: x + self.step_x,
                          lambda y: y,
                          lambda row: row,
                          lambda col: col + 1,
                          lambda x, y: x < new_x,
                          lambda: (self.col  == (self.grid.cells_x - 1)) or
                                                self.grid.wall_present(r, c, 
                                                                      'right'),
                          (self.images.right1, self.images.right2))

    def left(self):
        r = self.row; c = self.col
        new_x = self.x - self.grid.cell_width
        return self.__move(lambda x: x - self.step_x,
                          lambda y: y,
                          lambda row: row,
                          lambda col: col - 1,
                          lambda x, y: x > new_x,
                          lambda: self.col == 0 or
                                  self.grid.wall_present(r, c, 'left'),
                          (self.images.left1, self.images.left2))
    def up(self):
        r = self.row; c = self.col
        new_y = self.y - self.grid.cell_height
        return self.__move(lambda x: x,
                          lambda y: y - self.step_y,
                          lambda row: row - 1,
                          lambda col: col,
                          lambda x, y: y > new_y,
                          lambda: self.row == 0 or
                                  self.grid.wall_present(r, c, 'up'),
                          (self.images.up1, self.images.up2))
    def down(self):
        r = self.row; c = self.col
        new_y = self.y + self.grid.cell_height
        return self.__move(lambda x: x,
                          lambda y: y + self.step_y,
                          lambda row: row + 1,
                          lambda col: col,
                          lambda x, y: y < new_y,
                          lambda: (self.row == (self.grid.cells_y - 1)) or
                                  self.grid.wall_present(r, c, 'down'),
                          (self.images.down1, self.images.down2))
    def timer(self):
        if (self.stop_sleep  == 1): 
            self.grid.canvas.delete('neko')
            self.grid.canvas.create_image(self.x, self.y,
                                          image=self.images.awake,
                                          tags='neko')
            self.grid.canvas.update()
            self.state = _AWAKE
            return

        if (self.state == _SLEEP1):
            self.state = _SLEEP2
            self.grid.canvas.delete('neko')
            self.grid.canvas.create_image(self.x, self.y,
                                          image=self.images.sleep2,
                                          tags='neko')
         #   self.grid.canvas.update()
        elif (self.state == _SLEEP2):
            self.state = _SLEEP1
            self.grid.canvas.delete('neko')
            self.grid.canvas.create_image(self.x, self.y,
                                          image=self.images.sleep1,
                                          tags='neko')
          #  self.grid.canvas.update()
        self.grid.canvas.after(_TIMER_STEP, self.timer)

    def disappear(self):
        self.grid.canvas.delete('neko')

    def appear(self):
        self.grid.canvas.create_image(self.x, self.y,
                                      image=self.images.awake,
                                      tags='neko')

    def neko_pos(self):
        return (self.row, self.col)
    
    def sleep(self):
        if self.state != _AWAKE:
            return
        self.stop_sleep = 0
        self.state = _SLEEP1
        self.grid.canvas.create_image(self.x, self.y,
                                      image=self.images.sleep1,
                                      tags='neko')
        self.grid.canvas.update()
        self.grid.canvas.after(_TIMER_STEP, self.timer)
    
    def wakeup(self):
        self.stop_sleep = 1       


class Mouse:
    def __init__(self, grid):
        self.alive = 0
        self.grid = grid
        self.img = BitmapImage(data=bitmaps['mouse'])

    def mouse_pos(self):
        if self.alive:
            return (self.row, self.col)
        else:
            return (-1, -1)

    def mouse_at(self, r, c):
        return self.alive and (self.row == r) and (self.col == c)

    def place_mouse(self, r=3, c=3):
        if self.grid.neko.neko_pos() == (r, c):
            return  "There is Neko in that cell ... I won't go there!!"
        if self.alive:
            self.grid.canvas.delete('mouse')
        self.alive = 1
        self.row = r 
        self.col = c 
        self.x = self.col * self.grid.cell_width + \
                 (self.grid.cell_width / 2)
        self.y = self.row * self.grid.cell_height + \
                 (self.grid.cell_height / 2)
        self.grid.canvas.create_image(self.x, self.y,
                                      image=self.img, tags='mouse')
        self.grid.canvas.update()

    def kill_mouse(self):
        self.alive = 0
        self.grid.canvas.delete('mouse')
        self.grid.canvas.update()

class Window:
	
	def __init__(self):
		
		global grid
		self.menu = 0
		self.grid_obj = Grid()
		grid = self.grid_obj
		


def right():
    global grid
    return grid.neko.right()


def left():
    global grid
    return grid.neko.left()

def up():
    global grid
    return grid.neko.up()

def down():
    global grid
    return grid.neko.down()

def sleep():
    global grid
    return grid.neko.sleep()

def wakeup():
    global grid
    return grid.neko.wakeup()

def disappear():
    global grid
    return grid.neko.disappear()

def appear():
    global grid
    return grid.neko.appear()

def place_mouse(r, c):
    global grid
    return grid.mouse.place_mouse(r, c)

def kill_mouse():
    global grid
    return grid.mouse.kill_mouse()

def mouse_at(r, c):
    global grid
    return grid.mouse.mouse_at(r, c)

def mouse_pos():
    global grid
    return grid.mouse.mouse_pos()

def build_wall(r, c, direction):
    global grid
    return grid.build_wall(r, c, direction)

def destroy_wall(r, c, direction):
    global grid
    return grid.destroy_wall(r, c, direction)

def wall_present(r, c, direction):
    global grid
    return grid.wall_present(r, c, direction)


if __name__ == "__main__":
	r = Tk()
	r.title('PyNeko.1.0')
	grid = Grid()
	r.mainloop()
