# -*- coding: UTF-8 -*-
"""
This is the graphical interface  for Apoo

Copyright (C) 1998-2003 Rogério Reis & Nelma Moreira {rvr,nam}@ncc.up.pt

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   

@author: Rogério Reis & Nelma Moreira {rvr,nam}@ncc.up.pt
"""



#### path
import string, sys, os, tempfile, stat, posix, gzip
if sys.argv[0]:
    help_dir = os.path.dirname(sys.argv[0])
    if not help_dir:
        help_dir = os.getcwd()
else:
    help_dir=os.getcwd()

### other system imports
import signal

#### Tk and alike imports
from Tkinter import *             # widget classes
from ScrolledText import ScrolledText
from tkFileDialog import *
from Dialog import  Dialog
from types import *             # type constants

### Vpu imports
from vpu import *
from constants import *
import constants, vpu, vpu_tutor

### Versions
version="$Revision: 1.26 $"
vpu_version = vpu.__version
vpu_tutor_version =vpu_tutor.__version
constants_version = constants.__version

#### define constants
APOO='apoo'
CantBreak='Cannot set a break point in line'
CantClearBreak='Cannot clear a break point in line'
#pid_file = os.environ['HOME'] + "/apoo.pid"
pid_file = "/tmp/apoo.pid"

#### Color definitions
Colour_tags = [('currentline', 'white',None),
    ('errorline', 'red', None),
    ('label', None, 'brown'),
    ('inst', None, 'grey'),
    ('breakp', None, 'darkolivegreen4')
    ]

#### define interface
class VpuInterface(Frame):
    def __init__(self,pu,filename,master=None):
        Frame.__init__(self,master)
        self.pack(expand=YES, fill=BOTH)
        self.defback=self.cget('background')
        self.start(pu)
        self.makeTopBar()                    
        self.makeMessageBar()
        self.makeWidgets()
        if filename:
            self.filename=filename
            if os.path.exists(filename):
                self.fileRead(pu)
                if (self.Load(pu)==0):
                    self.Run(pu)
        else:
            self.filename=""
            
    #interface objects   
    def makeTopBar(self):
        self.topbar = Frame(self, cursor='hand2', relief=SUNKEN, bd=2)
        self.topbar.pack(side=TOP, expand=YES, fill=X)
        for item in self.topBar:
            self.tbw[item[0]] = Button(self.topbar, text=item[0],
                                       command=item[1])
            self.tbw[item[0]].config(underline=item[6])
            self.tbw[item[0]].pack(item[2])
            self.bind_all(item[4],item[5])
#            self.bind(item[4],item[5])
            self.tbw[item[0]].bind("<Enter>",item[3])
            self.tbw[item[0]].bind("<Leave>",self.clean_message)
            
    def makeControlBar(self,master):
        for item in self.controlBar: 
            self.cbw[item[0]]=Button(master, text=item[0], command=item[1])
            self.cbw[item[0]].pack(expand=YES,fill=BOTH)
            self.cbw[item[0]].bind("<Enter>",item[2])
            self.cbw[item[0]].bind("<Leave>",self.clean_message)
            self.cbw[item[0]].config(state='disabled')

    def makeMessageBar(self):
        self.message=Label(self,background='white',font=self.msgfont)
        self.message.pack(side=BOTTOM,fill=X,padx=3,pady=10)

    def makeWidgets(self):
        self.frameprg=Frame(self)
        self.frameprg.pack(side=TOP,padx=3, pady=3, expand=YES, fill=BOTH)
        self.frameprg.program=Frame(self.frameprg)
        self.frameprg.program.grid(row=0,column=0,
                                    padx=3, pady=3, sticky='nsew')
        self.makeProgram( self.frameprg.program) 
        self.frameprg.control=Frame(self.frameprg)
        self.frameprg.control.grid(row=0,column=1,
                                   padx=3, pady=3, sticky='nsew')
        self.makeControlBar(self.frameprg.control) 
        self.framereg=Frame(self)
        self.framereg.pack(side=LEFT,padx=3, pady=3,
                        expand=YES,  fill=X,  anchor='n')
        self.makeRegisters(self.framereg)
        self.framemem=Frame(self)
        self.framemem.pack(side=LEFT,padx=3, pady=3,
                           expand=YES, anchor='n', fill=X)
        self.makeMemory(self.framemem)
        self.framestack=Frame(self)
        self.framestack.pack(side=LEFT,padx=3, pady=3,
                           expand=YES, anchor='n')
        self.makeStack(self.framestack)

    def makeProgram(self,master):
        master.statusbar=Frame(master)
        master.statusbar.grid(row=0,column=2,padx=3, pady=3,
                              sticky='ew')
        master.statusbar.filel=Label(master.statusbar,
                                       text='File:',
                                     anchor=W)
        master.statusbar.filen=Label(master.statusbar,
                                       textvar=self.s_file,
                                       relief=FLAT,
                                       anchor='center',
                                       width=20,
                                       background='white'
                                        )
        master.statusbar.linel=Label(master.statusbar,
                                       text='Line:',
                                       anchor=W)
        master.statusbar.linen=Label(master.statusbar,
                                       textvar=self.statusline,
                                       relief=FLAT,
                                       anchor='center',
                                       width=7,
                                       background='white'
                                        )
        master.statusbar.statel=Label(master.statusbar,
                                       text='Status:',
                                       anchor=W)
        master.statusbar.staten=Label(master.statusbar,
                                       textvar=self.status,
                                       relief=FLAT,
                                       anchor='center',
                                       width=20,
                                       background='white'
                                        )
        master.statusbar.filel.grid(row=0,column=0,sticky=W+E)
        master.statusbar.filen.grid(row=0,column=1,sticky=W+E)
        master.statusbar.linel.grid(row=0,column=2,sticky=W+E)
        master.statusbar.linen.grid(row=0,column=3,sticky=W+E)
        master.statusbar.statel.grid(row=0,column=4,sticky=W+E)
        master.statusbar.staten.grid(row=0,column=5,sticky=W+E)
        
        master.vbar = Scrollbar(master, name='vbar')
        master.prog=Text(master,font=self.prgfont,
                         width=20,height=20,
                         tabs=('2c','4c','6c','8c','10c'),
                         name='prog')
        master.prog['yscrollcommand'] = master.vbar.set
        master.lines=Text(master,bd=2,width=4)
        master.lines['font']=self.prgfont,
        master.lines['yscrollcommand']= master.vbar.set
        master.addr=Text(master,bd=2,width=4,fg='blue')
        master.addr['font']=self.prgfont,
        master.addr['yscrollcommand']= master.vbar.set
        master.vbar['command'] = self.prog_yview
        Label(master,text='Line').grid(row=0,column=0,sticky='NSEW')
        master.lines.grid(row=1,column=0,sticky='NSEW')
        Label(master,text='Addr.').grid(row=0,column=1,sticky='NSEW')
        master.addr.grid(row=1,column=1,sticky='NSEW')
        master.prog.grid(row=1,column=2,sticky='NSEW')
        master.vbar.grid(row=1,column=3,sticky='NSEW')
        master.columnconfigure(0,weight=1)
        master.columnconfigure(1,weight=1)
        master.columnconfigure(2,weight=1)
        master.rowconfigure(1,weight=1)
        master.rowconfigure(0,weight=1)

        ###Bind
        if self.tester == 0:
            self.edittags=master.prog.bindtags()
            emacs_mode(master.prog)
            self.bind_edit()
        
        ###Tags
        for t,b, f in Colour_tags:
            master.prog.tag_configure(t,background=b)
            master.prog.tag_configure(t,foreground=f)

        ###Begins disabled
        master.prog.config(state='disabled')
        master.lines.config(state='disabled')
        master.addr.config(state='disabled')

    def makeRegisters(self,master):
        #PC
        self.pc=IntVar()
        master.framepc=Frame(master)
        master.framepc.pack(side=LEFT,expand='yes',anchor='n')
        master.framepc.labelpc=Message(master.framepc,
                                    width=100,
                                    anchor='n',
                                    text='Program Counter',
                                    font=self.bigfont,
                                    fg='red',justify=LEFT)
        master.framepc.labelpc.grid(row=0,column=0,pady=3,sticky='N')
        master.framepc.entrypc=Label(master.framepc,width=8,
                                      font=self.msgfont,
                                      fg='blue',
                                      relief='sunken',
                                      textvar=self.pc)
        master.framepc.entrypc.grid(row=1,column=0)

        self.timer=IntVar()
        master.framepc.labeltimer=Message(master.framepc,
                                    width=100,
                                    text='Timer',
                                    font=self.bigfont,
                                    fg='red',justify=LEFT)
        master.framepc.labeltimer.grid(row=3,column=0,pady=3,sticky='N')
        master.framepc.entrytimer=Label(master.framepc,width=8,
                                      font=self.msgfont,
                                      fg='black',
                                      relief='sunken',
                                      textvar=self.timer)
        master.framepc.entrytimer.grid(row=4,column=0)

        master.frameregs=Frame(master)
        master.frameregs.pack(side=LEFT,expand=YES,fill=BOTH,anchor='n')
        master.frameregs.title=Label(master.frameregs,text='Registers',
                           anchor='n',
                           fg='red',
                           height=2,
                           font=self.bigfont
                           )
        master.frameregs.title.grid(row=0, column=0, pady=3, columnspan=2,
                                    sticky='WE')
        for i in xrange(self.nreg):
            si='%s' %(i)
            ri='R'+si
            Label(master.frameregs, width=3,text=ri).grid(row=i+2,column=0)
            Label(master.frameregs,width=8,
                  relief='sunken',
                  anchor=W,
                  font=self.prgfont,
                  fg="black",
                  textvar=self.regs[i]).grid(row=i+2,column=1,sticky='WE')

    def makeMemory(self,master):
        master.title=Label(master,text='Memory Data',
                           anchor='center',
                           fg='red',
                           font=self.bigfont
                           )
        master.labell=Label(master, text='Label')
        master.addressl=Label(master, text='Address')
        master.contentsl=Label(master,text='Contents')
        master.label=Listbox(master)
        master.address=Listbox(master)
        master.contents=Listbox(master)
        master.scroll = Scrollbar(master)
        master.label.config(yscrollcommand=master.scroll.set,
                              fg='brown',
                              font=self.prgfont,
                              width=8,
                              height=9,
                             relief=SUNKEN)
        master.address.config(yscrollcommand=master.scroll.set,
                              fg='blue',
                              font=self.prgfont,
                              width=3,
                              height=9,
                              relief=SUNKEN)
        master.contents.config(yscrollcommand=master.scroll.set,
                               fg="black",
                               font=self.prgfont,
                               width=10,
                               height=9,
                               relief=SUNKEN)
        master.scroll.config(command= self.mem_yview, relief=SUNKEN)
        master.title.grid(row=0,column=0,columnspan=3,pady=3,sticky='nsew')
        master.labell.grid(row=1,column=0,sticky='nsew',padx=2)
        master.addressl.grid(row=1,column=1,sticky='nsew',padx=2)
        master.contentsl.grid(row=1,column=2,sticky='nsew',padx=2)
        master.label.grid(row=2,column=0,sticky='nsew',padx=2)
        master.address.grid(row=2,column=1,sticky='nsew',padx=2)
        master.contents.grid(row=2,column=2,sticky='nsew',padx=2)
        master.scroll.grid(row=2,column=3,sticky='nsew')
        #Bind
        master.label.bindtags([])
        master.address.bindtags([])
        master.contents.bindtags([])

    def makeStack(self,master):
        master.title=Label(master,text='System Stack',
                           anchor='n',
                           fg='red',
                           height=2,
                           font=self.bigfont)
        master.contents=Listbox(master)
        master.scroll = Scrollbar(master)
        master.contents.config(yscrollcommand=master.scroll.set,
                               fg="black",
                               font=self.prgfont,
                               width=10,
                               height=9,
                               relief=SUNKEN)
        master.scroll.config(command= self.stack_yview, relief=SUNKEN)
        master.title.grid(row=0,column=0,columnspan=2,pady=3,sticky='n')
        master.contents.grid(row=3,column=0,sticky='nsew',padx=2)
        master.scroll.grid(row=3,column=1,sticky='nsew')
        #Bind
        master.contents.bindtags([])


    #interface aux

    def set_short_name(self):
        short_fn=string.split(self.filename,'/')
        short_fn=short_fn[len(short_fn) - 1]
        self.s_file.set(short_fn)

    def set_current_line(self):
        last=self.frameprg.program.prog.index('end -1 chars')
        last=string.split(last,".")
        last=last[0]
        self.statusline.set("%s:%s" %(self.line,last))
        
    def set_edit_line(self,e=None):
        last=string.split(self.frameprg.program.prog.index('end -1 chars'),
                          ".")[0]
        curr=string.split(self.frameprg.program.prog.index('insert'),".")[0]
        self.statusline.set("%s:%s" %(curr,last))
        
    def mem_yview(self,*args):
        apply(self.framemem.contents.yview,args)
        apply(self.framemem.address.yview,args)
        apply(self.framemem.label.yview,args)

    def stack_yview(self,*args):
        apply(self.framestack.contents.yview,args)

    def prog_yview(self,*args):
        apply(self.frameprg.program.prog.yview,args)
        apply(self.frameprg.program.lines.yview,args)
        apply(self.frameprg.program.addr.yview,args)
   
    def i_yview(self,lw,*args):
        for i in lw:
            apply(i.yview,args)
            
    #showing information 
    def write_message(self,mes,cor):
        self.message.config(text=mes,background=cor) 

    def clean_message(self,event):
        if self.status.get()=='ready':
            self.message.config(text="",background='white')
        
    def show_labels(self,pu):
        self.frameprg.program.addr.config(state='normal')
        self.frameprg.program.addr.delete('1.0',END)
        last=self.frameprg.program.prog.index('end -1 chars')
        last=string.split(last,".")
        last=int(last[0])
        for i in xrange(last):
            li="%s.0" %i
            try:
                line=pu.lines.index(i)
                li="%s.0" %i
                self.frameprg.program.addr.insert(li,"%s\n" %line)
            except:
                self.frameprg.program.addr.insert(li,"\n")
                continue
        self.frameprg.program.addr.config(state='disabled')

    def show_pc(self,pc):
        self.pc.set(pc)

    def show_timer(self,timer):
        self.timer.set(timer)
        
    def show_regs(self,regs):
        for i in xrange(len(regs)):
            self.regs[i].set(regs[i])
    
    def show_mem(self,pu):
        self.framemem.label.delete(0,END)
        self.framemem.address.delete(0,END)
        self.framemem.contents.delete(0,END)
        for i in xrange(len(pu.RAM)):
            self.framemem.label.insert(END,' ')
            self.framemem.address.insert(END,i)
            self.framemem.contents.insert(END,pu.RAM[i])
        for x in pu.labelm.keys():
            self.framemem.label.delete(pu.labelm[x])
            self.framemem.label.insert(pu.labelm[x],'%s' %x)

    def show_stack(self,stack):
        self.framestack.contents.delete(0,END)
        for i in xrange(len(stack)):
            self.framestack.contents.insert(END,stack[i])

    def show_cpu(self,pu):
        self.show_mem(pu)
        self.show_regs(pu.reg)
        self.show_pc(pu.PC)
        self.show_timer(pu.time)
        self.show_stack(pu.stack)

    def control_one(self,func,mode):
        self.cbw[func].config(state=mode)
        
    def control(self,mode):
        for i in self.cbw.keys():
            self.cbw[i].config(state=mode)
            
    #File stuff
    def ReadTkTextOLD(self):
        a=StringVar()
        a.set(self.frameprg.program.prog.get('1.0',END))
        return a.get()

    def ReadTkText(self):
	a=self.frameprg.program.prog.get('1.0',END)
    	return a.encode("iso-8859-1")

    def read_prog(self,f):
        input = open(f, 'r')
        self.program = []
        linum = 0
        while 1:
            line = input.readline()
            linep = []
            linum = linum + 1
            self.frameprg.program.lines.insert(END,"%d\n"%linum)
            if not line: break
            self.frameprg.program.prog.insert(END,line)            
            if len(line) == 1: continue
            line = string.split(line)
            if line:
                if line[0][len(line[0])-1] == ':' and line[0][0] != '#':
                    linep.append(line[0][:len(line[0])-1])
                    first='%s.%s' %(linum,0)
                    last='%s.%s' %(linum,len(line[0])-1)
                    self.frameprg.program.prog.tag_add('label',first,last)
                elif line[0][0] == '#':
                    continue
                else:
                    linep.append([])
                    linep.append(line[0])
                for i in xrange(1,len(line)):
                    if line[i][0] == '#': continue
                    else: linep.append(line[i])
                self.program.append((linum,linep))
        #lock text
        self.frameprg.program.prog.config(state='disabled')
        self.frameprg.program.lines.config(state='disabled')
        self.frameprg.program.addr.config(state='disabled')

    def Init_config(self):
        self.framemem.address.config(background=self.defback)
        self.framemem.label.config(background=self.defback)
        self.framemem.contents.config(background=self.defback)
        self.framestack.contents.config(background=self.defback)

        
    def LastMem(self):
        n=self.framemem.address.size()
        sn='%s' %n
        self.framemem.address.see(sn)
        self.framemem.label.see(sn)
        self.framemem.contents.see(sn)
        self.framemem.address.config(background='red')
        self.framemem.contents.config(background='red')
        self.framemem.label.config(background='red')
        
        
    def Clean_Run(self):
        self.status.set("end of program")
        self.control_one('Step','disabled')
        self.control_one('Run','disabled')
        self.control_one('Continue','disabled')
        self.control_one('Clear','disabled')
        self.bind_program(1)
        
    def Clean_Loaded(self,pu):
        pu.clean()
        self.ClearAllBreak(pu)
        self.frameprg.program.prog.tag_remove('currentline',1.0,END)
        self.Init_config()
        self.show_cpu(pu)
        self.control('disabled')
        self.state['load']=0
        self.bind_program(1)
        self.status.set('ready')
        self.clean_message(None)
        
    def Not_Save(self):
         if self.state['save']==0:
            if self.filename:
                que='Do you want save changes in file %s?' %self.filename
            else:
                que='Do you want save changes in edited file?'
            todo=question('Previous File Edited',que,0,'question',
                          ('Yes','No','Cancel'))
            if todo == 1:
                return
            if todo == 2:
                raise 'Cancel'
            if todo == 0:
                if self.filename:
                    self.fileSave()
                else:
                  self.fileSaveAs()

    def fileRead(self,pu):
        if self.state['load']==1:
            self.Clean_Loaded(pu)
        if self.status.get()=="parsing error":
            self.frameprg.program.prog.tag_remove('errorline',1.0,END)
        self.frameprg.program.prog.config(state='normal')
        self.frameprg.program.lines.config(state='normal')
        self.frameprg.program.addr.config(state='normal')
        self.frameprg.program.prog.delete('1.0',END)
        self.frameprg.program.addr.delete('1.0',END)
        self.frameprg.program.lines.delete('1.0',END)
        self.read_prog(self.filename)
        self.set_edit_line()
        self.set_short_name()
        mes="Open File " + self.filename
        self.write_message(mes,'white')
        self.control('disabled')
        self.control_one('Load','normal')
        self.state['save']=1
        self.status.set('ready')


    def fileOpen(self,pu):
        try:
            self.Not_Save()
        except 'Cancel':
            return
        fn=askopenfilename(filetypes=[("apoo", "*.apoo"),("all","*")])
        if fn:
            self.filename=fn
            self.fileRead(pu)
            
    def fileNew(self,pu):
        try:
            self.Not_Save()
        except 'Cancel':
            return
        self.frameprg.program.prog.config(state='normal')
        self.frameprg.program.prog.delete('1.0',END)
        self.filename=""
        self.set_short_name()
        mes="New File"
        self.write_message(mes,'white')
        self.state['save']=0
        self.Editmode(pu)

    def fileExample(self,pu,fn):
        try:
            self.Not_Save()
        except 'Cancel':
            return
        if fn:
            self.filename=fn
            self.fileRead(pu)
            
    def TempSave(self):
        file=open(self.tmpfile, 'w')
        file.write(self.ReadTkText())

    def TempRemove(self):
         if os.path.exists(self.tmpfile):
            os.unlink(self.tmpfile)
        
    def fileSave(self):
        if self.filename:
            file=open(self.filename, 'w')
            file.write(self.ReadTkText())
            mes="Saved File " + self.filename
            self.write_message(mes,'white')
            self.state['save']=1
        else:
           self.write_message("No File to Save",'red')
           
    def fileSaveAs(self):
        text=self.ReadTkText()
        l=len(text)
        if (l<=1):
            self.write_message("No Text Program to Save",'red')
            return
        fn=asksaveasfilename(initialfile=self.filename)
        if fn:
            self.filename=fn
            file=open(self.filename, 'w')
            file.write(text)
            self.set_short_name()
            mes="Saved File " + self.filename
            self.write_message(mes,'white')
            self.state['save']=1
    #Edit

    def Editmode(self,pu):
        self.bind_edit()
        self.frameprg.program.lines.config(state='normal')
        self.frameprg.program.lines.delete('1.0',END)
        self.frameprg.program.lines.config(state='disabled')
        self.frameprg.program.addr.config(state='normal')
        self.frameprg.program.addr.delete('1.0',END)
        self.frameprg.program.addr.config(state='disabled')
        if self.status.get()=="parsing error":
            self.frameprg.program.prog.tag_remove('errorline',1.0,END)
        if self.state['load']==1:
            self.Clean_Loaded(pu)
        self.control_one('Load','normal')
        self.status.set("editing")
        self.set_edit_line()
        self.frameprg.program.prog.focus()        
        self.state['save']=0

    
    
    #Control
            
    def Load(self,pu):
        if self.status.get()=='editing':
            try: 
                self.TempSave()
            except IOError:
                self.write_message('Can not open temporary file','red')
                return
            self.frameprg.program.lines.config(state='normal')
            self.frameprg.program.addr.config(state='normal')
            self.frameprg.program.prog.delete('1.0',END)
            self.frameprg.program.addr.delete('1.0',END)
            self.frameprg.program.lines.delete('1.0',END)
            if os.path.exists(self.tmpfile):
                self.read_prog(self.tmpfile)
            else:
                self.write_message('Can load program','red')
                return
        if self.state['load']==1:
            self.Clean_Loaded(pu)
        self.bind_program(0)
        self.status.set("loading")
        try:
            pu.load(self.program)
        except vpuLoadError,error:
            self.proc_except(error.message,error.line)
            return
        except:
            self.write_message('Error:%s ,%s' %(sys.exc_type,sys.exc_value),'red')
            self.status.set("parsing error")
            return
        self.turn_off('currentline',self.line)
        try:
            self.line=pu.lines[pu.PC]
            self.turn_on('currentline',self.line)
            self.set_current_line()
        except IndexError:
            self.write_message(OutOfProgram,'red')
        self.show_cpu(pu)
        self.show_labels(pu)
        self.write_message('Program Loaded','white')
        self.control('normal')
        self.status.set("loaded")
        self.state['load']=1
        return 0
        
    def Run(self,pu):
        try:
            pu.run(self.maxsteps)
        except OutOfMemory, error:
            self.write_message("%s: memory address %s not reserved"
                          %(error.message,error.add), error.colour)
            self.LastMem()
            self.Clean_Run()
        except vpuError, error:
            self.write_message(error.message,error.colour)
            self.Clean_Run()
        except:
            self.write_message('Error:%s ,%s' %(sys.exc_type,sys.exc_value),
                          'red')
            self.Clean_Run()
        self.turn_off('currentline',self.line)
        try:
            self.line=pu.lines[pu.PC]
            self.turn_on('currentline',self.line)
            self.set_current_line()
        except IndexError:
            pass
        self.show_cpu(pu)
        self.status.set("end of program")
        
    def Step(self,pu):
        self.write_message('Next Step','white')
        self.status.set("running")
        try:
            pu.step()
        except OutOfMemory, error:
            self.write_message("%s: memory address %s not reserved"
                          %(error.message,error.add), error.colour)
            self.LastMem()
            self.Clean_Run()
        except vpuError, error:
            self.write_message(error.message, error.colour)
            self.Clean_Run()
        except:
            self.write_message('Error:%s ,%s' %(sys.exc_type,sys.exc_value),'red')
            self.Clean_Run()
        self.turn_off('currentline',self.line)
        try:
            self.line=pu.lines[pu.PC]
            self.turn_on('currentline',self.line)
            self.set_current_line()
        except IndexError:
            self.turn_on('currentline',self.line)
            self.set_current_line()
        self.show_cpu(pu)


    def Is_BreakPoint(self,pu,line):
       try:
           i=pu.lines.index(line)
       except ValueError:
           return 0
       try:
           b=pu.BreakP.index(i)
       except ValueError:  
           return 0
       return 1
   
    def Cont(self,pu):
        self.write_message('Continue Program','white')
        try:
            pu.cont(self.maxsteps)
        except OutOfMemory, error:
            self.write_message("%s: memory address %s not reserved"
                          %(error.message,error.add), error.colour)
            self.LastMem()
            self.Clean_Run()
        except vpuError, error:
            self.write_message(error.message, error.colour)
            self.Clean_Run()
        except:
            self.write_message('Error:%s ,%s' %(sys.exc_type,sys.exc_value),'red')
            self.Clean_Run()
        self.turn_off('currentline',self.line)
        try:
            self.line=pu.lines[pu.PC]
            self.turn_on('currentline',self.line)
            self.set_current_line()
            if self.Is_BreakPoint(pu,self.line):
                self.status.set("at break point")
            else:
                self.status.set("end of program")
        except IndexError:
            pass
        self.show_cpu(pu)
   
    def ClearAllBreak(self,pu):
            pu.BreakP=[]
            self.frameprg.program.prog.tag_remove('breakp',1.0,END)
        
    def ClearBreakPoint(self,pu,event=None):
        line=string.split(self.frameprg.program.prog.index('current'),'.')[0]
        line=int(line)
        try:
            i=pu.lines.index(line)
        except ValueError:
            self.write_message("%s %s"%(CantClearBreak,line),'white')
            return
        try: 
            pu.clearbreak(i)
            self.turn_off('breakp',line)
        except:
            self.write_message('Error:%s ,%s' %(sys.exc_type,sys.exc_value),'red')
            return

    def SetBreakPoint(self,event,pu):
        line=string.split(self.frameprg.program.prog.index('current'),'.')[0]
        line=int(line)
        try:
            i=pu.lines.index(line)
        except ValueError:
            self.write_message("%s %s"%(CantBreak,line),'white')
            return
        try:
            pu.setbreak(i)
            self.turn_on('breakp',line)
        except:
            self.write_message('Error:%s ,%s' %(sys.exc_type,sys.exc_value),
                               'red')
            return

    def proc_except(self,e,m):
        self.turn_on('errorline',m)
        erro= "%s line: %d"%(e,m)
        self.write_message(erro,'red')
        self.status.set("parsing error")
    
    
    def turn_on(self,tag,l):
        li='%s.0' %l
        lf='%s.0 lineend' %l
        ls='%s' %(l-2)
        self.frameprg.program.prog.tag_add(tag,li,lf)
        self.frameprg.program.lines.tag_add(tag,li,lf)
        self.frameprg.program.prog.see(li)
        self.frameprg.program.lines.see(li)
        self.frameprg.program.addr.see(li)

    def turn_off(self,tag,l):
        li='%s.0' %l
        lf='%s.end lineend' %l
        ls='%s' %(l-2)
        self.frameprg.program.prog.tag_remove(tag,li,lf)
        self.frameprg.program.lines.tag_remove(tag,li,lf)

    def bind_program(self,l):
            if l == 0:
                self.frameprg.program.prog.config(state='disabled')
                self.frameprg.program.prog.bindtags((self.frameprg.program.prog, 'all'))
                for item in self.programBind:
                    self.frameprg.program.prog.bind(item[0],"")
                    self.frameprg.program.prog.bind(item[0],item[1])
                for item in self.editBind:
                     self.frameprg.program.prog.bind(item[0],"")
            else:
                # self.frameprg.program.prog.config(state='disabled')
                for item in self.programBind:
                    self.frameprg.program.prog.bind(item[0],"")
        

    def bind_edit(self):
        self.frameprg.program.prog.config(state='normal')
        self.frameprg.program.prog.bindtags(self.edittags)
        for item in self.editBind:
            self.frameprg.program.prog.bind(item[0],"")
            self.frameprg.program.prog.bind(item[0],item[1])
            
    def quit(self):
        try:
            self.Not_Save()
        except 'Cancel':
            return
        self.TempRemove()
        que='Are you sure you want to quit?'
        ans=question('Verify quit',que,0)
        if ans == 0:
            Frame.quit(self)



    def help_file(self,file,title,icon):
        global help_dir
        if os.path.exists(help_dir):
            hf=help_dir+os.sep+file
            if os.path.isfile(hf):
                new  = Toplevel()
                new.resizable(width=0,height=0)
                new.title(title)
                new.iconname(icon)
                text = ScrolledText(new, height=30, font=self.prgfont,
                                          width=90)  #1.2
                text.pack()
                b=Button(new,text='Dismiss',command=new.destroy)
                if file[-3:] == ".gz":
                    text.insert('1.0', gzip.open(hf, 'r').read() )
                else:
                    text.insert('1.0', open(hf, 'r').read() )
                text.config(state='disabled')
                text.window_create(1.0,window=b)

        
    def assembly(self):
        self.help_file('help_ass.txt.gz','Apoo Assembly Language','Help')

    def help_apoo(self):
        self.help_file('help_apoo.txt','Apoo Interface Help %s'%version,'Help')
        
    def about_apoo(self):
        new  = Toplevel()
        new.resizable(width=0,height=0)
        new.title("Apoo revisions")
        new.iconname("About")
        text = Text(new, height=20, font=self.prgfont,
                            width=50)  #1.2
        b=Button(new,text='Dismiss',command=new.destroy)
        text.tag_configure("title",foreground="red")
        text.tag_configure("title",font=self.bigfont)
        text.insert(END, "                                       Apoo\n\n")
        text.tag_add('title','1.0','1.0 lineend')
        text.insert(END,"            An environment for a first course\n")
        text.insert(END,"            in assembly language programming \n\n")
        text.insert(END,"            (c) 1998 Rogério Reis & Nelma Moreira\n")
        text.insert(END,"                        {rvr,nam}@ncc.up.pt\n\n")
        text.insert(END,"            DCC-FC & LIACC, Universidade do Porto\n\n" )
        text.insert(END,"                     http://www.ncc.up.pt/apoo\n\n")
        text.insert(END, "%s\n"%version )
        text.insert(END, "%s\n"%vpu_version )
        text.insert(END, "%s\n"%vpu_tutor_version )
        text.insert(END, "%s\n"%constants_version)
        text.insert(END, "\n\n" )
        text.config(state='disabled')
        text.window_create(END,window=b)
        text.pack()



    def help_button(self,mes):
        if self.status.get()=='ready':
            self.write_message(mes,'white')
    
    def start(self,pu):
        self.nreg=pu.nreg
        self.maxmem=1000
        self.maxsteps=1000
        self.pc=IntVar()
        self.regs={}
        self.mem={}
        self.line=0
        for i in xrange(self.nreg):
            self.regs[i]=IntVar()
        for i in xrange(self.maxmem):
            self.mem[i]=IntVar()      
        self.program=[]
        self.tmpfile=tempfile.mktemp()
        self.msgfont="-*-Times-Bold-r-*-*-*-180-*-*-*-*-ISO8859-1"
        self.bigfont="-*-Times-Bold-r-*-*-*-180-*-*-*-*-ISO8859-1"
        self.prgfont="-*-Times-Bold-r-*-*-*-140-*-*-*-*-ISO8859-1"
        self.topbar(pu)
        self.cbw={} 
        self.controlBar = [
            ('Load',lambda x=self, u=pu: x.Load(u),
             lambda  e, x=self:
                   x.help_button('Load a Program into Memory; First Open, Create/Edit a File')
             ),
            ('Run',lambda x=self, u=pu: x.Run(u),
             lambda  e, x=self:
                   x.help_button('Run a Program in Memory Ignoring Break Points')),
            ('Step',lambda x=self, u=pu: x.Step(u),
              lambda  e, x=self:
                   x.help_button('Execute the Next Instruction of the Program in Memory')),
            ('Continue',lambda x=self, u=pu: x.Cont(u),
             lambda  e, x=self:
                   x.help_button('Execute Instructions until the Next Break Point')),
            ('Clear', lambda x=self,u=pu: x.ClearAllBreak(u),
             lambda  e, x=self:  x.help_button('Clear all breakpoints, setted with Double-B1 in a line'))
            ]
        self.bindes(pu)
        self.s_file=StringVar()
        self.statusline=StringVar()
        self.status=StringVar()
        self.status.set('ready')
        self.state={}
        self.state['save']=1
        self.state['load']=0


class VpuWorkBench(VpuInterface):
    def __init__(self,pu,filename,master=None):
        VpuInterface.__init__(self,pu,filename,master)

    def topbar(self,pu):
        self.tester=0
        self.tbw={} 
        self.topBar = [
            ('Quit',self.quit, {'side': LEFT},
             lambda  e, x=self:
             x.help_button('Quit Apoo Interface'),
             "<Control-q>", lambda e, x=self: x.quit(),0),
            ('Open',lambda x=self,u=pu:x.fileOpen(u),{'side': LEFT},
             lambda  e, x=self:
             x.help_button('Open a File'),
             "<Control-o>",lambda e, x=self,u=pu:x.fileOpen(u),0),
            ('New', lambda  x=self,u=pu: x.fileNew(u), {'side': LEFT},
             lambda  e, x=self:
             x.help_button('Create a New File to Edit'),
             "<Control-n>", lambda  e, x=self,u=pu: x.fileNew(u),0),
            ('Save',self.fileSave,
              {'side': LEFT},
             lambda  e, x=self:
             x.help_button('Save the Edited File'),
             "<Control-s>", lambda e, x=self:x.fileSave(),0),
            ('SaveAs',self.fileSaveAs,{'side': LEFT},
             lambda  e, x=self:
             x.help_button('Save as the Edited File'),
             "<Control-v>", lambda e,x=self:x.fileSaveAs(),2),
            ('Edit',lambda x=self, u=pu: x.Editmode(u),{'side': LEFT},
             lambda  e, x=self:
             x.help_button('Enter Edit Mode'),
             "<Control-i>",lambda e,x=self, u=pu: x.Editmode(u),2),
            ('About', self.about_apoo, {'side':RIGHT},
             lambda  e, x=self:
             x.help_button('Revisions of Apoo modules'),
             "<Control-a>",lambda e,x=self:x.about_apoo(),0),
            ('Help', self.help_apoo, {'side':RIGHT},
             lambda  e, x=self:
             x.help_button('Brief Description of the Apoo Interface'),
             "<Control-h>",lambda e,x=self:x.help_apoo(),0),
            ('Assembly Language',self.assembly, {'side':RIGHT},
             lambda  e, x=self:
             x.help_button('Description of the Assembly Instructions'),
             "<Control-u>",lambda e,x=self:x.assembly(),13)]


    def bindes(self,pu):
        self.programBind = [
            ('<Double-1>',
                      lambda  e, x=self, u=pu: x.SetBreakPoint(e,u)),
            ('<Double-2>',
                      lambda e,x=self, u=pu: x.ClearBreakPoint(u,e)),
            ]
        self.editBind = [
            ('<Any-Key>',
             lambda e, x=self: x.set_edit_line(e))
            , ('<Button>',
               lambda e, x=self: x.set_edit_line(e))
            ]


        

class VpuTester(VpuInterface):
    def __init__(self,pu,filename,master=None):
        self.vpu=pu
        VpuInterface.__init__(self,pu,filename,master)

    def topbar(self,pu):
        self.tester=1
        self.tbw={}
        self.topBar = [
            ('Quit',self.realy_quit, {'side': LEFT},
             lambda  e, x=self:
             x.help_button('Quit Apoo Interface'),
             "<Control-q>", lambda e, x=self: x.realy_quit(),0),
            ('Help', self.help_tester, {'side':RIGHT},
             lambda  e, x=self:
             x.help_button('Brief Description of the Apoo Tester'),
             "<Control-h>",lambda e,x=self:x.help_tester(),0),
            ('Assembly Language',self.assembly, {'side':RIGHT},
             lambda  e, x=self:
             x.help_button('Description of the Assembly Instructions'),
             "<Control-u>",lambda e,x=self:x.assembly(),13)]
        

    def bindes(self,pu):
        self.programBind = [
            ('<Double-1>',
                      lambda  e, x=self, u=pu: x.SetBreakPoint(e,u)),
            ('<Double-2>',
                      lambda e,x=self, u=pu: x.ClearBreakPoint(u,e)),
            ]
        self.editBind = []
            
    def handlerA(self,*args):
        self.fileRead(self.vpu)
        if (self.Load(self.vpu)==0):
            self.Run(self.vpu)
            
    def handler_quit(self,*args):
#        print "handler_quit", args
        self.realy_quit()
        
    def realy_quit(self):
        os.remove(pid_file)
        Frame.quit(self)

    def help_tester(self):
        self.help_file('help_tester.txt','Apoo Tester Help','Help')

#global functions

def question(title, text, default=1, bitmap='question', strings=('Yes', 'No')):
        d=Dialog(None, 
                      title  = title, 
                      text   = text, 
                      bitmap = bitmap, 
                      default= default, strings=strings)
        return d.num

    
def main(filename,mode):
    pu=Vpu(8)
    root=Tk()
    root.option_add('*Background','#CCCCCC')
    root.option_add('*Foreground','black')
    root.resizable(width=0,height=0)
    if mode == 'tester':
        root.title('Apoo Tester')
        interface=VpuTester(pu,filename,root)
        signal.signal(signal.SIGUSR2,interface.handlerA)
        signal.signal(signal.SIGQUIT,interface.handler_quit)
        root.protocol("WM_DELETE_WINDOW",interface.realy_quit)
    else:
        root.title('Apoo Workbench')
        interface=VpuWorkBench(pu,filename,root)
        root.protocol("WM_DELETE_WINDOW",interface.quit)
    interface.mainloop()

def properfile(filename):
    if not os.path.exists(filename): # File doesn't exist
        sys.stderr.write("%s: %s not found\n" %(APOO,filename))
        sys.exit(1)
    mode= posix.stat(filename)[stat.ST_MODE]
    if not stat.S_ISREG(mode):  # or it's not readable
        sys.stderr.write("%s not readable\n"%path)
        sys.exit(1)

def  help_mode():
     sys.stderr.write("usage: %s [-options] [filename]\n"%APOO)
     sys.stderr.write("Options are:\n")
     sys.stderr.write("        --help,  -h Print this message\n")
     sys.stderr.write("        --tester, -t Runs Apoo Tester with filename (mandatory)\n\n")
     sys.stderr.write("Without options runs Apoo Workbench, possible loading filename\n")

def register_pid():
    file = open(pid_file,'w')
    file.write("%d"%os.getpid())
    file.close()
        
def testerStuff():
    try: file = open(pid_file,'r')
    except IOError:    # file doesn't exist
        register_pid()
    else:
        pid = int(file.readline())
        file.close()
        try: os.kill(pid,signal.SIGQUIT)
        except OSError:
            pass
        register_pid()
        
## emacs-mode
        
Clipboard=""

def emacs_mode(w):
    w.bind('<Control-k>', lambda e, w=w: kill_line(w))
    w.bind('<Control-y>', lambda e, w=w: yank(w))
    w.bind('<Control-w>', lambda e, w=w: kill_region(w))
    w.bind('<Escape>w', lambda e, w=w: copy_region_as_kill(w))
    w.bind('<Control-at>', lambda e, w=w: set_mark_command(w))
    w.bind('<Control-a>', lambda e, w=w: beginning_of_line(w))
    w.bind('<Control-e>', lambda e, w=w:end_of_line(w))
    w.bind('<Control-less>', lambda e, w=w: beginning_of_buffer(w))
    w.bind('<Control-greater>', lambda e, w=w: end_of_buffer(w))


    
def kill_line(w):
    global Clipboard
    
    Clipboard=w.get('insert','insert lineend')    
    w.delete('insert','insert lineend')   
    return "break"


def yank(w):
    w.insert('insert',Clipboard)
    return "break"

def set_mark_command(w):
    w.mark_unset('kill_ring')
    w.mark_set('kill_ring','insert')
    return "break"
    
def kill_region(w):
    global start, end
    start=''
    end=''
    copy_region_as_kill(w)
    if start!='' and end!='': 
        w.delete(start,end)
    w.tag_delete('sel')
    return "break"

def copy_region_as_kill(w):
    global Clipboard, start, end
    try:
        start=w.index('sel.first')
        end=w.index('sel.last')
    except:
        if 'kill_ring' in w.mark_names():
            if w.compare('kill_ring','<','insert'):
                start='kill_ring'
                end='insert'
            else:
                start='insert'
                end='kill_ring'
        else:
            return
        
    Clipboard=w.get(start,end)
    return 

def end_of_buffer(w):
    w.mark_set('insert','end')
    w.see('insert')
    return "break"
    
def beginning_of_buffer(w):
    w.mark_set('insert',1.0)
    w.see('insert')
    return "break"


def beginning_of_line(w):
    curr=string.split(w.index('insert'),".")[0]
    w.mark_set('insert',    'insert linestart')
    return "break"

def end_of_line(w):
    w.mark_set('insert','insert lineend')
    return "break"


if __name__ == '__main__':
    filename = ""
    argc = len(sys.argv)
    if argc > 1:
        if sys.argv[1] == '--help' or sys.argv[1] == '-h':
            help_mode()
            sys.exit(0)
        elif sys.argv[1] == '--tester' or sys.argv[1]=='-t':
            mode='tester'
            testerStuff()
            if argc == 3:    
                properfile(sys.argv[2])
                filename=sys.argv[2]
            else:       
                sys.stderr.write('Usage: %s %s filename\n'%(APOO,sys.argv[1]))
                sys.exit(1)
        elif argc == 2:
            properfile(sys.argv[1])
            filename = sys.argv[1]
            mode = 'workbench'
        else:
            sys.stderr.write('For usage: %s --help\n'%APOO)
            sys.exit(1)
    else:     
        mode='workbench'
    main(filename,mode)
