#!/usr/bin/env python


from Tkinter import *
import thread
import traceback

from pNbody import *

########################################  
#					  
# History class				  
#					  
######################################## 

class History:
  '''
  History class
  '''

  def __init__(self,file):

    if os.path.isfile(file):
      self.f = open(file,'r+')
      self.cmds = self.f.readlines()
    else:
      self.f = open(file,'w')
      self.cmds = []
      
    self.file = file  
    self.index = len(self.cmds)    

  def add(self,cmd):
    self.cmds.append(cmd)
    self.f.write('%s\n'%cmd)
    self.f.flush()
    # force index to be the last index + 1
    self.index = len(self.cmds)
    
  def get(self):
    return self.cmds[self.index]  

  def up(self):
    if self.index < len(self.cmds)-1:
      self.index = self.index + 1
  
  def down(self):
    if self.index > 0:
      self.index = self.index - 1
          
  def close(self):
    self.f.close()  
  
  def write(self):
    f = open(self.file,'w')
    for cmd in self.cmds:
      f.write('%s\n'%cmd)
    f.close()  
    


########################################  
#					  
# Gcmd class				  
#					  
######################################## 

class Gcmd:

    def __init__(self):

        
	self.gather_functions() 


        if mpi.mpi_IsMaster():
	
	
    	  # init history
     	  self.init_hist()     
	
	
          self.root = Tk()
          
	  # create frames
          self.create_main_frame()
	  self.create_display_frame(0,2)
	  self.create_cmdwin_frame(1,0,1,1)
	  self.create_cmd_frame(0,4,1,1)
	  	  
	  self.root.mainloop()
	  
	else:
	  self.WaitForACommand()
	   
	    
	    
	    
	    
	    
    def gather_functions(self):
      '''
      This function gather all available functions of the class
      and record it into the dictionary self.allfct
      '''
      
      fs = dir(self)		 
      self.allfct = {}	   
      for f in fs:
    	exec("func = self.%s"%(f))			  # here it could be better
    	if type(func) == types.MethodType:
    	  self.allfct[f] = func   
	  



    def quit(self,*arg,**kw):
      self.BroadcastCmd("quit",arg,kw)
      '''
      exit function
      '''		
		
      sys.exit()	
      
      	     

    def sayhello(self,*arg,**kw):
      self.BroadcastCmd("sayhello",arg,kw)
      '''
      hello function
      '''	
      print "hello, I am proc %d"%(ThisTask)	
	  
	  
	  
	  
	  
    def WaitForACommand(self,*arg,**kw):	
      
      # wait for the command
      name = MPI.WORLD.Recv(source = 0) 
      arg  = MPI.WORLD.Recv(source = 0) 
      kw   = MPI.WORLD.Recv(source = 0) 
      
      # now, execute the command
      apply(self.allfct[name],arg,kw)
      
     
      # recursive call
      self.WaitForACommand()	# !!! here, we have the rist to never quit !!!
      #thread.start_new_thread(self.WaitForACommand,arg,kw)
	

    def BroadcastCmd(self,name,arg,kw):
      
      if mpi.mpi_IsMaster():
    
      	for Task in range(1,NTask):
    	  MPI.WORLD.Send(name, dest = Task)
    	  MPI.WORLD.Send(arg, dest = Task)
    	  MPI.WORLD.Send(kw, dest = Task)
       

    ########################################
    #
    # init
    #
    ########################################

    ###########################
    def init_hist(self):
    ###########################
      '''
      init history
      '''
      self.hist = History(os.path.join(HOME,'.ginterhist'))


    ########################################
    #
    # create some frames
    #
    ########################################

    ###########################
    def create_main_frame(self): 
    ###########################     
      '''
      create the main frame
      '''
      
      self.main_frame = Frame(self.root,highlightbackground='black')
      self.main_frame.pack()

    ###########################
    def create_display_frame(self,x,y):      
    ###########################
      '''
      create the display frame
      '''
      self.display_frame = Frame(self.main_frame,bg='black',highlightbackground='black')
      self.display_frame.grid(column=x,row=y)
    								   
      self.canvas1 = Gcan(self.display_frame,height=self.params.get('shape')[1],width=self.params.get('shape')[0],bg="black",highlightbackground='black') 
      self.canvas1.grid(column=0,row=0)
      
      self.canvas1.init(self.params,root=self,eye='left' ,twin=None) 
    	   
 

    ###########################
    def create_cmdwin_frame(self,x,y,dx,dy):	  
    ###########################
      '''
      create the cmdwin frame
      '''
      self.cmdwin_frame = Frame(self.main_frame,relief=RIDGE,borderwidth=1)
      self.cmdwin_frame.grid(column=x,row=y,columnspan=dx,rowspan=dy,sticky=N)


      # quit button												
      self.quitBut = Button(self.cmdwin_frame,text="QUIT",fg="black",width=16,height=2,command=lambda:self.quit()) 		      
      self.quitBut.grid(column=0,row=0,sticky=E+N+S+W)  						
      
      # reset button												
      self.resetBut = Button(self.cmdwin_frame,text="RESET",fg="black",width=16,height=2,command=lambda:self.sayhello())			      
      self.resetBut.grid(column=0,row=1,sticky=E+N+S+W)     

   
    ###########################
    def create_cmd_frame(self,x,y,dx,dy):      
    ###########################
      '''
      create the cmd frame
      '''

      def ok(arg):
    	

    	goodcmd = 1
    	cmd = self.command_entry.get()
	
    	try:
    	  self.execute_command(cmd)
    	except Exception,message:
	  print "try to run command = %s"%(cmd)
          traceback.print_tb(sys.exc_info()[2])
          print message 
    	  goodcmd = 0
    	
    	if goodcmd: 
    	  self.hist.add(cmd)
    	  self.command_entry.delete(0,len(self.command_entry.get())+1)
      
      
      def up(event):
    	self.hist.down()
    	cmd = string.strip(self.hist.get())
    	self.command_entry.delete(0,len(self.command_entry.get())+1)
    	self.command_entry.insert(INSERT,cmd)

      def down(event):
    	self.hist.up()
    	cmd = string.strip(self.hist.get())
    	self.command_entry.delete(0,len(self.command_entry.get())+1)
    	self.command_entry.insert(INSERT,cmd)	 
    	
      def cancel():
    	pass

      self.cmd_frame = Frame(self.main_frame,relief=RIDGE,borderwidth=1)
      self.cmd_frame.grid(column=x,row=y,columnspan=dx,rowspan=dy,sticky=N)	  
    										
      
      # entry command								
      self.command_entry = Entry(self.cmd_frame,width=72)				     
      self.command_entry.grid(column=1,row=0,sticky=N+S+E+W) 
      self.command_entry.bind("<Return>",ok) 
      self.command_entry.bind("<Down>",down)
      self.command_entry.bind("<Up>",up)
    	  

    ###########################
    def execute_command(self,*arg,**kw):	
    ###########################
      self.BroadcastCmd("execute_command",arg,kw)
      '''
      execute a command
      '''
      exec(arg[0])








gcmd = Gcmd()
