#Created by dan december 2011.  www.danomagnum.com
#from Tkinter import Tk, Frame, BOTH, RIGHT, LEFT, RAISED, Label, IntVar, BooleanVar, X, RAISED, Menu, Scrollbar,Y, Scrollbar, TclError, N, S
from Tkinter import *
#from ttk import Button, Style, Scale
from ttk import Scale
import ladder_tk
import time
import pickle
import copy
import tkFileDialog

FORMATS = [('Python Ladder Logic','*.pll')]

class AutoScrollbar(Scrollbar):
	# a scrollbar that hides itself if it's not needed.  only
	# works if you use the grid geometry manager.
	def set(self, lo, hi):
		if float(lo) <= 0.0 and float(hi) >= 1.0:
				# grid_remove is currently missing from Tkinter!
				self.tk.call("grid", "remove", self)
		else:
				self.grid()
		Scrollbar.set(self, lo, hi)
	def pack(self, **kw):
		raise TclError, "cannot use pack with this widget"
	def place(self, **kw):
		raise TclError, "cannot use place with this widget"



class MainWindow(Frame):
	def __init__(self, parent):
		Frame.__init__(self, parent, background="white")
		self.parent = parent
		self.rungs = []
		self.exspeed = 100
		self.paused = False
		self.initUI()
		self.updatesize = False
		self.calculating = False
	def initUI(self):
		#this sets up the interface, and then goes into the program part
		#self.parent.title("PyLadderLogic")
		#self.style = Style()
		#self.style.theme_use("default")
		#self.pack(fill=BOTH,expand=1)
		self.grid(row=0,column=0,sticky='news')
		ladder_tk.fix_scroll = self.scrollsizeupdate
		ladder_tk.remove_row = self.removerows

		#sc = Scrollbar(self)
		#sc.pack(side=RIGHT,fill=Y)

		topperfrm = Frame(self)
		topperfrm.pack(fill=X,expand=1)
		spdlbl = Label(topperfrm,text="Speed^-1")
		spdlbl.pack(side=LEFT)
		scale = Scale(topperfrm, from_=50, to=1000, command=self.onScale,value=100)
		scale.pack(side=LEFT)

		spdlbl = Button(topperfrm,text="Play/Pause",command=self.playpause)
		spdlbl.pack(side=RIGHT)
		button1 = Button(topperfrm,text="Run one loop",command=self.runone)
		button1.pack(side=RIGHT)
		button1 = Button(topperfrm,text="Update",command=self.toggleit)
		button1.pack(side=RIGHT)



		topfrm = Frame(self)
		topfrm.pack(fill=X,expand=1)



		self.popup = Menu(root,tearoff=0)
		self.popup.add_command(label='Add Rung',command=self.addrung)
		self.popup.add_command(label='Save',command=self.save)
		self.popup.add_command(label='Load',command=self.load)
		root.config(menu=self.popup)


		#this section defines the "bits" in the "plc" and a few 10-bit words
		I0 = ladder_tk.value_word(0,"I0:0")
		I0.bits_display_new(topfrm)
		self.I0 = I0.bits()
		self.I0[0].set(True)
		self.I0[1].set(True)
		self.I0[2].set(True)
		self.I0[6].set(True)
		ladder_tk.itemlist += self.I0

		topfrm2 = Frame(self)
		topfrm2.pack(fill=X,expand=1)


		B0 = ladder_tk.value_word(0,"B0:0")
		B0.bits_display_new(topfrm2)
		self.B0 = B0.bits()
		ladder_tk.itemlist += self.B0

		topfrm4 = Frame(self)
		topfrm4.pack(fill=X,expand=1)

		O0 = ladder_tk.value_word(0,"O0:0")
		O0.bits_display_new(topfrm4)
		self.O0 = O0.bits()
		ladder_tk.itemlist += self.O0


		topfrm3 = Frame(self)
		topfrm3.pack(fill=X,expand=1)

		W0 = ladder_tk.value_word(0,"W0")
		W1 = ladder_tk.value_word(10,"W1")
		W2 = ladder_tk.value_word(1,"W2")
		W3 = ladder_tk.value_word(0,"W3")
		W4 = ladder_tk.value_word(0,"W4")
		W5 = ladder_tk.value_word(0,"W5")
		W6 = ladder_tk.value_word(0,"W6")
		self.Words = [W0,W1,W2,W3,W4,W5,W6]
		for w in self.Words:
			w.display_new(topfrm3)

		ladder_tk.itemlist += self.Words
		
		self.dataforms = [topfrm,topfrm2,topfrm4,topfrm3]

	def addrung(self):
		r = ladder_tk.rung()
		self.rungs.append(r)
		r.display_new(self)

	def toggleit(self):
		#this function is named this because I just kept reusing it, so no reason.
		#self.bv.set(random.randint(0,1023))
		#print self.bv
		#self.bv.display_update()
		#self.blk1.display_update()
		#for r in self.rungs:
			#r.display_update()
		#self.update_idletasks()
		#canvas.config(scrollregion=canvas.bbox("all"))
		#print self.A0
		self.removedata()

	def runone(self):
		#do one run through the ladder
		self.paused = True
		for r in self.rungs:
			r.run()
			r.display_update()
		
	def onScale(self, val):
		#set the speed
		speed = int(float(val))
		self.exspeed = int(float(val))

	def playpause(self):
		#toggle the play/pause
		self.paused = not self.paused

	def scrollsizeupdate(self):
		#print "test"
		#canvas.config(scrollregion=canvas.bbox("all"))
		self.updatesize=True

	def removerows(self,row):
		pausestate = self.paused
		self.paused = True
		while self.calculating:
			time.sleep(.1)
		self.rungs.remove(row)
		row.__del__()
		self.paused = pausestate

	def removedata(self):
		pausestate = self.paused
		self.paused = True
		while self.calculating:
			time.sleep(.1)
		self.I0 = None
		self.B0 = None
		self.O0 = None
		ladder_tk.itemlist = []
		dfs = self.dataforms[:]
		for f in dfs:
			f.destroy()
		self.dataforms = []
		self.paused = pausestate

	def save(self):
		filename = tkFileDialog.asksaveasfilename(parent=root,filetypes=FORMATS,title="Save")
		if not filename:
			return False
		
		pausestate = self.paused
		self.paused = True

		while self.calculating:
			time.sleep(.1)

		dfs = self.dataforms[:]
		#print dfs
		for f in dfs:
			f.destroy()



		#filename = "test.pll"

		f = open(filename,'w')
		output = self.rungs
		for o in output:
			o.pickleprepare()
		for i in self.I0:
			i.pickleprepare()
		for i in self.B0:
			i.pickleprepare()
		for i in self.O0:
			i.pickleprepare()
		for w in self.Words:
			w.pickleprepare()
		pickle.dump([output,self.I0,self.B0,self.O0,self.Words],f)
		f.close()

		#for o in output:
			#self.removerows(o)
		
		#self.load(filename=filename)
		
		self.dataforms = []
		self.reinit()
		self.paused = pausestate

	def load(self):
		filename = tkFileDialog.askopenfilename(parent=root,filetypes=FORMATS,title="Save")
		if not filename:
			return False
		rows = self.rungs[:]
		for r in rows:
			self.removerows(r)
		self.removedata()
		f = open(filename,'r')
		[self.rungs,self.I0,self.B0,self.O0,self.Words] = pickle.load(f)
		f.close()
		self.reinit()
		self.updatesize=True

	def reinit(self):
		for rung in self.rungs:
			rung.postpickle()
		for item in self.I0:
			item.postpickle()
		for item in self.B0:
			item.postpickle()
		for item in self.O0:
			item.postpickle()
		for item in self.Words:
			item.postpickle()

		ladder_tk.itemlist = []

		topfrm = Frame(self)
		topfrm.pack(fill=X,expand=1)
		for i in self.I0:
			i.display_new(topfrm)
		ladder_tk.itemlist += self.I0
		self.dataforms.append(topfrm)

		topfrm = Frame(self)
		topfrm.pack(fill=X,expand=1)
		for i in self.B0:
			i.display_new(topfrm)
		ladder_tk.itemlist += self.B0
		self.dataforms.append(topfrm)


		topfrm = Frame(self)
		topfrm.pack(fill=X,expand=1)
		for i in self.O0:
			i.display_new(topfrm)
		ladder_tk.itemlist += self.O0
		self.dataforms.append(topfrm)


		topfrm = Frame(self)
		topfrm.pack(fill=X,expand=1)
		for i in self.Words:
			i.display_new(topfrm)
		ladder_tk.itemlist += self.Words
		self.dataforms.append(topfrm)


		for r in self.rungs:
			r.display_new(self)
			r.display_update()


def calculatron(*args):
	#this is what automatically executes the logic at whatever interval is set
	app = args[0]
	if not app.paused:
		app.calculating = True
		for r in app.rungs:
			r.run()
			r.display_update()
		app.calculating = False
	root.after(app.exspeed,calculatron,app)
def scrollbarupdate(*args):
	app = args[0]
	if app.updatesize:
		canvas.config(scrollregion=canvas.bbox("all"))
		app.updatesize = False
	root.after(100,scrollbarupdate,app)

def OnMouseWheel(event):
	d = 0
	if event.num == 5 or event.delta == -120:
		d = 1
	elif event.num == 4 or event.delta == 120:
		d = -1
	canvas.yview("scroll", d, "units")

root = Tk()
vscrollbar = AutoScrollbar(root)
vscrollbar.grid(row=0,column=1, sticky=N+S)
hscrollbar = AutoScrollbar(root, orient=HORIZONTAL)
hscrollbar.grid(row=1, column=0, sticky=E+W)
canvas = Canvas(root, yscrollcommand=vscrollbar.set, xscrollcommand=hscrollbar.set,width=1000,height=300)
canvas.grid(row=0, column=0, sticky=N+S+E+W)

root.bind('<MouseWheel>', OnMouseWheel)
root.bind('<Button-4>', OnMouseWheel)
root.bind('<Button-5>', OnMouseWheel)

vscrollbar.config(command=canvas.yview)
hscrollbar.config(command=canvas.xview)

root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0,weight=1)

frame = Frame(canvas)
frame.rowconfigure(1, weight=1)
frame.columnconfigure(1,weight=1)


#rows = 5
#for i in range(1,rows):
    #for j in range(1,10):
        #button = Button(frame, padx=7, pady=7, text="[%d,%d]" % (i,j))
        #button.grid(row=i, column=j, sticky='news')


app = MainWindow(frame)
canvas.create_window(0, 0, anchor=NW, window=frame)
frame.update_idletasks()
canvas.config(scrollregion=canvas.bbox("all"))
app.update_idletasks()
root.after(100,calculatron,app)
root.after(100,scrollbarupdate,app)
root.mainloop()
