import matplotlib
matplotlib.use("WXAgg")
matplotlib.interactive(True)
from matplotlib.backends.backend_wxagg import Toolbar, FigureCanvasWxAgg
from matplotlib.figure import Figure
from matplotlib.axes import Subplot
 
import wx
import wx.lib.newevent
import threading
import time
import os
import ezdaq
import copy

ID_STARTBUTTON=101
ID_CONFIGUREBUTTON=103
ID_STOPBUTTON=104
ID_OKBUTTON=105
ID_CLEARBUTTON=106
X_INIT = [0,12000]
Y_INIT = [-.1,.1]
SAVEFILE="damping.dat"


# this creates an UpdateCanvasEvent even class that will get created
# and sent from the worker thread to the main thread (which is the
# only place that updates to the GUI should happen...lest there be crashes)
(UpdateCanvasEvent, EVT_UPDATE_CANVAS) = wx.lib.newevent.NewEvent()

class MainWindow(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self,None,-1,"Seismometer Damping")

        self.arrayLock = threading.Semaphore(1)	
	self.canvasLock = threading.Semaphore(1)

	#create the preferences window
	self.prefwindow = self.createPreferencesWindow()
	
	#create the canvas
	self.figure = Figure((10,4),75)
	self.canvas = FigureCanvasWxAgg(self, -1, self.figure)
        self.toolbar = Toolbar(self.canvas)
        self.toolbar.Realize()
        
	#create and configure all buttons
	self.startButton = wx.Button(self, ID_STARTBUTTON, "Start")
	wx.EVT_BUTTON(self, ID_STARTBUTTON, self.pressStartButton)

        self.stopButton = wx.Button(self, ID_STOPBUTTON, "Stop")
	self.stopButton.Enable(0)
	wx.EVT_BUTTON(self, ID_STOPBUTTON, self.pressStopButton)

	configureButton = wx.Button(self, ID_CONFIGUREBUTTON, "Configure")
	wx.EVT_BUTTON(self, ID_CONFIGUREBUTTON, self.pressConfigureButton)

	
	#add buttons to the horizontal sizer:
        self.sizerHoriz = wx.BoxSizer(wx.HORIZONTAL)
        self.sizerHoriz.Add(self.startButton,0,wx.ALL,border=5)
        self.sizerHoriz.Add(self.stopButton,0,wx.ALL,border=5)
	self.sizerHoriz.Add(configureButton,0,wx.ALL,border=5)
	
        # Use some sizers to see layout options
        self.sizerVert=wx.BoxSizer(wx.VERTICAL)
        self.sizerVert.Add(self.sizerHoriz,0,wx.EXPAND)
	self.sizerVert.Add(self.canvas,1,wx.ALL)
        self.sizerVert.Add(self.toolbar,0,wx.GROW)

	#Bind the update canvas event to some function:
	self.Bind(EVT_UPDATE_CANVAS, self.onUpdateCanvas)
	
        #Layout sizers
        self.SetSizer(self.sizerVert)
        self.SetAutoLayout(1)
        self.sizerVert.Fit(self)
	self.initialize()
        self.Show(1)

    def charge_digital_out(self):
        self.configuration = self.prefwindow.getConfiguration()
        ezdaq.configure_device(self.configuration)
        ezdaq.configure_dio(self.configuration)
        ezdaq.configure_streaming(self.configuration)
        ezdaq.set_bit(self.configuration["digital"][0][0], 1)	

    def release_digital_out(self):
	print "release_digital_out()"
        self.worker = helperThread(self)
	print "1"
        ezdaq.start_streaming()
	print "2"
        ezdaq.set_bit(self.configuration["digital"][0][0], 0)
	print "3"
        self.worker.start()
	print "4"
	self.stopButton.Enable(1)
	print "5"

    def clear_screen(self):
	self.arrayLock.acquire()
	self.xarray = copy.deepcopy(X_INIT)
	self.yarray = copy.deepcopy(Y_INIT)
        self.line.set_data(self.xarray,self.yarray)
	self.arrayLock.release()
	evt = UpdateCanvasEvent()
	wx.PostEvent(self, evt)

    def pressStartButton(self, event):
	self.clear_screen()
	self.startButton.Enable(0)
	self.charge_digital_out()
	release_timer = threading.Timer(10.0,self.release_digital_out)
	release_timer.start()
	

    def pressStopButton(self, event):
        self.stopButton.Enable(0)
        self.worker.stopFlag=0
        self.worker.join()
        ezdaq.stop_streaming()
        ezdaq.close_device()
	self.startButton.Enable(1)

    def export_to_file(self):
        myfile = open(SAVEFILE,'w')
        self.arrayLock.acquire()
        for i in range(len(self.xarray)):
            myfile.write("%(x)s\t%(y)s\n" % {'x':self.xarray[i], 'y':self.yarray[i]})
        self.arrayLock.release()
        myfile.close()
    
    def pressConfigureButton(self, event):
	self.prefwindow.Show(1)
	self.prefwindow.MakeModal(1)

    def createPreferencesWindow(self):
	prefwindow = PreferencesFrame(self, "Preferences") 
	prefwindow.CentreOnParent(wx.BOTH)
	return prefwindow

    def initialize(self):
   	self.subplot = self.figure.add_subplot(111)
	self.xarray = copy.deepcopy(X_INIT)
	self.yarray = copy.deepcopy(Y_INIT)
        self.line, = self.subplot.plot(self.xarray,self.yarray,'.')
        self.toolbar.update()

    def onUpdateCanvas(self, evt):
	print "Updating the canvas..."
	self.canvasLock.acquire()
	self.canvas.draw()
        self.toolbar.update()
	self.canvasLock.release()

    def GetToolBar(self):
        return self.toolbar

class helperThread(threading.Thread):
    def __init__(self,window):
        threading.Thread.__init__(self)
	self.window = window

    def run(self):
	print "Inside thread run method"
	self.stopFlag = 1
	while(self.stopFlag):
            try:
                newlists = ezdaq.get_results()
                if(newlists==None):
                    print "Waiting..."
                    time.sleep(1)
                    continue
            except IOError:
                print "Fatal Error"
                break
            print "Got the data."
            newylist = newlists[0]
            print len(newylist)
            self.window.arrayLock.acquire()
            self.window.yarray.extend(newylist)
            self.window.xarray.extend(range(len(self.window.xarray)+1,
					    len(self.window.xarray)+len(newylist)+1))
            self.window.line.set_data(self.window.xarray,self.window.yarray)
            self.window.arrayLock.release()
            evt = UpdateCanvasEvent()
            wx.PostEvent(self.window, evt)


class PreferencesFrame(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, -1, title)

        #p = wx.Panel(self, -1)
	vertSizer = wx.BoxSizer(wx.VERTICAL)
	titleLabel = wx.StaticText(self,-1, "Comedi Configuration")
	okButton = wx.Button(self, ID_OKBUTTON, "Save Changes")
	wx.EVT_BUTTON(self, ID_OKBUTTON, self.PressOkButton)

	sizer = wx.GridSizer(6,2,2,2) #rows, columns, hgap, vgap

	vertSizer.Add(titleLabel,0,wx.ALIGN_CENTER|wx.ALL,8)
	vertSizer.Add(sizer)
	vertSizer.Add(okButton,0,wx.ALIGN_RIGHT|wx.ALL,15)

	deviceNameLabel = wx.StaticText(self, -1, "Device: ")
	self.deviceNameTextBox = wx.TextCtrl(self, -1, "/dev/comedi0")
	sizer.Add(deviceNameLabel,0,wx.ALIGN_RIGHT)
	sizer.Add(self.deviceNameTextBox)

	inputSubdeviceLabel = wx.StaticText(self,-1, "Input Subdevice type: ")
	self.inputSubdeviceBox = wx.Choice(self,-1, choices=['COMEDI_SUBD_AI','COMEDI_SUBD_AO',
							'COMEDI_SUBD_DI','COMEDI_SUBD_DO',
							'COMEDI_SUBD_DIO'])
	self.inputSubdeviceBox.SetSelection(0)
	self.inputSubdeviceBox.Enable(0)
	sizer.Add(inputSubdeviceLabel,0,wx.ALIGN_RIGHT)
	sizer.Add(self.inputSubdeviceBox)

	inputChannelLabel = wx.StaticText(self, -1, "Analog Input Channel: ")
	self.inputChannelBox = wx.Choice(self,-1, choices=['0','1','2','3','4','5','6','7'])
	self.inputChannelBox.SetSelection(0)
	sizer.Add(inputChannelLabel,0,wx.ALIGN_RIGHT)
	sizer.Add(self.inputChannelBox)

	inputRangeLabel = wx.StaticText(self, -1, "Analog Input Range: ")
	self.inputRangeBox = wx.Choice(self,-1, choices=['0','1','2','3'])
	self.inputRangeBox.SetSelection(0)
	sizer.Add(inputRangeLabel,0,wx.ALIGN_RIGHT)
	sizer.Add(self.inputRangeBox)

	inputTypeLabel = wx.StaticText(self, -1, "Analog Input Type: ")
	self.inputTypeBox = wx.Choice(self,-1, choices=['AREF_GROUND','AREF_COMMON','AREF_DIFF'])
	self.inputTypeBox.SetSelection(2)
	sizer.Add(inputTypeLabel,0,wx.ALIGN_RIGHT)
	sizer.Add(self.inputTypeBox)

        inputPeriodLabel = wx.StaticText(self, -1, "Samples per second: ")
        self.inputPeriodBox = wx.TextCtrl(self,-1,"1000")
        sizer.Add(inputPeriodLabel,0,wx.ALIGN_RIGHT)
        sizer.Add(self.inputPeriodBox)

	outputSubdeviceLabel = wx.StaticText(self,-1, "Output Subdevice type: ")
	self.outputSubdeviceBox = wx.Choice(self,-1, choices=['COMEDI_SUBD_AI','COMEDI_SUBD_AO',
							'COMEDI_SUBD_DI','COMEDI_SUBD_DO',
							'COMEDI_SUBD_DIO'])
	self.outputSubdeviceBox.SetSelection(4)
	self.outputSubdeviceBox.Enable(0)
	sizer.Add(outputSubdeviceLabel,0,wx.ALIGN_RIGHT)
	sizer.Add(self.outputSubdeviceBox)

	outputChannelLabel = wx.StaticText(self, -1, "Digital Output Channel: ")
	self.outputChannelBox = wx.Choice(self,-1, choices=['0','1','2','3','4','5','6','7'])
	self.outputChannelBox.SetSelection(0)
	sizer.Add(outputChannelLabel,0,wx.ALIGN_RIGHT)
	sizer.Add(self.outputChannelBox)

        self.SetSizer(vertSizer)
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
        self.Fit()

    def PressOkButton(self,event):
	self.Close(1)

    def OnCloseWindow(self, event):
        self.MakeModal(False)
        self.Show(0)
	print self.getConfiguration()
        #self.Destroy()

    def getConfiguration(self):
	config = dict()
	config["device"] = self.deviceNameTextBox.GetValue()
	
        config["analog_period_ns"] = int(1e9/float(self.inputPeriodBox.GetValue()))

        analog_channel = int(self.inputChannelBox.GetStringSelection())
        range = int(self.inputRangeBox.GetStringSelection())
        aref = self.inputTypeBox.GetStringSelection()
        config["analog"] = [[analog_channel,range,aref]]

        digital_channel = int(self.outputChannelBox.GetStringSelection())
        config["digital"]=[[digital_channel, "COMEDI_OUTPUT"]]
	return config

app = wx.PySimpleApp()
frame = MainWindow()
app.MainLoop()
