#

import os, sys
import time
import glob

from PyQt4 import QtGui, QtCore, uic
from PyQt4.QtCore import SIGNAL, Qt

if "-m" in sys.argv:
    from gpib_plotter_mockup import GPIBplotter
else:
    from gpib_plotter import GPIBplotter
from hpgl_qt import QHPGLPlotterWidget
import hpgl_plotter_rc

ldir = os.path.abspath(os.path.dirname(__file__))
sys.path.append(ldir)
form_class, base_class = uic.loadUiType(os.path.join(ldir, "qhpgl_plotter.ui"))

from qpreferences import BaseItem, IntItem, UnicodeItem, ColorItem
from qpreferences import PointItem, SizeItem, ByteArrayItem
from qpreferences import AbstractPreferences
from qpreferenceseditor import PreferencesEditor

from tools import str_num_cmp

class Preferences(AbstractPreferences):
    ORGANISATION="Logilab"
    APPLICATION="qgpib_plotter"

    _pos = PointItem()
    _size = SizeItem()
    _appState = ByteArrayItem()

    device = UnicodeItem(default='/dev/ttyUSB0',
                         name=u'device',
                         description=u'GPIB device',
                         group="GPIB settings")
    address = IntItem(default=5, min=0, max=16,
                      name=u'GPIB address',
                      group="GPIB settings")
    
    background = ColorItem(default=QtGui.QColor("white"),
                           name="Background",
                           group="Colors")
    color0 = ColorItem(default=QtGui.QColor("black"),
                       name="Pen #0",
                       group="Colors")
    color1 = ColorItem(default=QtGui.QColor("green"),
                       name="Pen #1",
                       group="Colors")
    color2 = ColorItem(default=QtGui.QColor("red"),
                       name="Pen #2",
                       group="Colors")
    color3 = ColorItem(default=QtGui.QColor("blue"),
                       name="Pen #3",
                       group="Colors")
    color4 = ColorItem(default=QtGui.QColor("yellow"),
                       name="Pen #4",
                       group="Colors")
    color5 = ColorItem(default=QtGui.QColor("cyan"),
                       name="Pen #5",
                       group="Colors")
    color6 = ColorItem(default=QtGui.QColor("magenta"),
                       name="Pen #6",
                       group="Colors")
    color7 = ColorItem(default=QtGui.QColor("darkred"),
                       name="Pen #7",
                       group="Colors")
    
class QtHPGLPlotter(QtGui.QMainWindow, form_class):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self, parent)
        self._plots = {}        
        self._prefs = Preferences()
        self.setupUi()
        self.initializeGPIB()
        if self._prefs._pos:
            self.move(self._prefs._pos)
        if self._prefs._size:
            self.resize(self._prefs._size)
        if self._prefs._appState:
            self.restoreState(self._prefs._appState)
        self.readPreferences()

    def readPreferences(self):
        bg = self._prefs.background
        if bg and bg.isValid():
            self.plotterWidget.qview.setBackgroundBrush(QtGui.QBrush(bg))
        pen_colors = [self._prefs["color%d"%i] for i in range(8)]
        self.plotterWidget.pen_colors = pen_colors
        
    def replotCurrent(self):
        self.currentPlotChanged(self.plotsView.currentIndex())
        
    def setupUi(self):
        form_class.setupUi(self, self) # call qtdesigner generated form creation        
        # actions defined in designer
        self.connect(self.actionPreferences, SIGNAL('triggered(bool)'),
                     self.preferencesTriggered)
        self.connect(self.actionQuit, SIGNAL('triggered(bool)'),
                     self.quitTriggered)
        self.actionQuit.setShortcut(QtGui.QKeySequence(u'Ctrl+Q'))
        self.connect(self.actionOpen, SIGNAL('triggered(bool)'),
                     self.openTriggered)
        self.actionOpen.setShortcut(QtGui.QKeySequence(u'Ctrl+O'))
        self.connect(self.actionSave, SIGNAL('triggered(bool)'),
                     self.saveTriggered)
        self.actionSave.setShortcut(QtGui.QKeySequence(u'Ctrl+S'))
        self.connect(self.actionSaveAs, SIGNAL('triggered(bool)'),
                     self.saveAsTriggered)

        self.plotterWidget = QHPGLPlotterWidget(self)
        self.setCentralWidget(self.plotterWidget)

        self.connect(self.captureButton, SIGNAL("toggled(bool)"),
                     self.captureToggled)

        self._plots_list = QtGui.QStringListModel()
        self.plotsView.setModel(self._plots_list)
        self.connect(self.plotsView, SIGNAL('activated(const QModelIndex&)'),
                     self.currentPlotChanged)
        self.connect(self.plotsView.selectionModel(),
                     SIGNAL('currentChanged(const QModelIndex&, const QModelIndex&)'),
                     self.currentPlotChanged)

    def currentPlotChanged(self, index, old_index=None):
        if index.isValid():
            value = unicode(self.plotsView.model().data(index, Qt.DisplayRole).toString())
            
            self.plotterWidget.clear()
            self.plotterWidget.parse(self._plots[value])
            
    def preferencesTriggered(self, checked=False):
        PreferencesEditor(self._prefs, self).exec_()
        self.readPreferences()
        self.replotCurrent()

    def quitTriggered(self, checked=False):
        self.close()

    def closeEvent(self, event):
        if 1:
        #if self.promptForSave():
            self._prefs._pos = self.pos()
            self._prefs._size = self.size()
            self._prefs._appState = self.saveState()
            event.accept()
        else:
            event.ignore()
        
    def openTriggered(self, checked=False):
        filenames = QtGui.QFileDialog.getOpenFileNames(self, "Open a HPGL file to display", '.', 'HPGL files (*.plt)\nAll files (*)')
        self.openFiles(filenames)
        if not self.plotsView.currentIndex().isValid():
            self.plotsView.setCurrentIndex(self.plotsView.model().index(0, 0))

    def openFiles(self, filenames):
        for filename in filenames:
            filename = str(filename)
            if os.path.exists(filename):
                data = open(filename).read()
                name = os.path.basename(filename)
                name = os.path.splitext(name)[0]
                lst = self.plotsView.model().stringList()
                lst.append(name)            
                self._plots[name] = data
                self.plotsView.model().setStringList(lst)
        
    def plotReceived(self, num):
        self._receiving = False
        self.setReceivingLed()
        plot, timestamp = self.captureThread.getPlot(num)
        name = "plot_%s"%(num)
        lst = self.plotsView.model().stringList()
        lst.append(name)            
        self._plots[name] = plot
        self.plotsView.model().setStringList(lst)

    def plotStarted(self):
        self._receiving = True
        self.setReceivingLed()
        
    def saveTriggered(self, checked=False):
        print "save"
        
    def saveAsTriggered(self, checked=False):
        index = self.plotsView.selectionModel().currentIndex()
        if index.isValid():
            filename = QtGui.QFileDialog.getSaveFileName(self, "Selecte a file name to save HPGL file", '.', 'HPGL files (*.plt)\nAll files (*)')
            n = index.row()
            value = unicode(self.plotsView.model().data(index, Qt.DisplayRole).toString())
            open(filename, 'w').write(self._plots[value])
            
        
    def initializeGPIB(self):
        self._online = False
        try:
            self.gpib_plotter = QGPIBplotter(device=self._prefs.device,
                                            address=self._prefs.address,
                                            )
            self.captureThread = GPIBReceiver(self.gpib_plotter)
            self.connect(self.captureThread, SIGNAL('plotReceived(int)'),
                         self.plotReceived)
            self.connect(self.captureThread, SIGNAL('plotStarted()'),
                         self.plotStarted)
            self.captureThread.start()
        except Exception, e:
            #print e
            self.gpib_plotter = None
        self.setCaptureLed()

    def captureToggled(self, state):
        if state:
            if self.gpib_plotter is None:
                self.initializeGPIB()
                if self.gpib_plotter is None:
                    QtGui.QMessageBox.critical(self, self.tr("GPIB error"),
                                               self.tr("<b>Unable to initialize GPIB connection</b>.<br>Please check your GPIB dongle and settings."))
                    self._online = False
                    self.setCaptureLed()
                    return
            self._online = True
            self.captureThread.startCapture()
        else:
            if self.captureThread:
                self.captureThread.stopCapture()
            self._online = False
        self.setCaptureLed()
        
    def setCaptureLed(self):
        if self._online:
            icn = QtGui.QIcon(':/icons/led_green.svg')
        else:
            icn = QtGui.QIcon(':/icons/led_green_off.svg')
        self.captureButton.setIcon(icn)
        self.captureButton.setChecked(self._online)

    def setReceivingLed(self):
        if self._receiving:
            icn = QtGui.QIcon(':/icons/led_red.svg')
        else:
            icn = QtGui.QIcon(':/icons/led_red_off.svg')
        self.receivingButton.setIcon(icn)

class QGPIBplotter(GPIBplotter):
    def __init__(self, device="/dev/ttyUSB0", baudrate=115200, timeout=0.1,
                 address=5):
        GPIBplotter.__init__(self, device, baudrate, timeout, address)        
        self.emitter = None

    def plotStarted(self):
        if self.emitter:
            self.emitter.emit(SIGNAL('plotStarted()'))
            #self.emitter.msleep(1)
        
class GPIBReceiver(QtCore.QThread):
    def __init__(self, cnx):
        QtCore.QThread.__init__(self)
        self.gpibplotter = cnx
        self.gpibplotter.emitter = self
        
        self._cancelmutex = QtCore.QMutex()
        self._cancel = False
        #self._nreceived = 0
        self._plotsmutex = QtCore.QMutex()
        self._plots = []
        self._startstopmutex = QtCore.QMutex()
        self._startstop = QtCore.QWaitCondition()
        self._capturing = False
        
    def cancel(self):
        self._cancelmutex.lock()
        self._cancel = True
        self._cancelmutex.unlock()

    def startCapture(self):
        self._startstop.wakeOne()

    def stopCapture(self):
        self._startstopmutex.lock()
        self._capturing = False
        self._startstopmutex.unlock()

    def run(self):
        while 1:
            self._cancelmutex.lock()
            if self._cancel:
                return
            self._cancelmutex.unlock()
            self._startstopmutex.lock()
            if not self._capturing:
                self._startstop.wait(self._startstopmutex)
                self._capturing = True
            self._startstopmutex.unlock()
        
            plot = self.gpibplotter.load_plot(wait_timeout=0.1)
            timestamp = time.time()
            if plot:
                self._plotsmutex.lock()
                self._plots.append((plot, timestamp))
                n = len(self._plots)
                self._plotsmutex.unlock()
                self.emit(SIGNAL('plotReceived(int)'), n-1)
            self.msleep(10)
            
    def getPlot(self, num):
        self._plotsmutex.lock()
        try:
            return self._plots[num]
        finally:
            self._plotsmutex.unlock()

def main():
    import optparse
    opt = optparse.OptionParser('A simple PyQt4 HP7470A GPIB plotter emulator for USB-GPIB bundle (ProLogix)')
    opt.add_option('-m', '--mockup', default=False,
                   action="store_true",
                   dest='mockup',
                   help='Use a pseudo GPIB connection (for test purpose)',
                   )
    opt.add_option('-v', '--verbose', default=False,
                   action="store_true",
                   dest="verbose",
                   help="Verbose mode",)
    
    options, argv = opt.parse_args(sys.argv)

    if options.verbose:
        sys.stderr.write('connection established\n')

    a = QtGui.QApplication(argv)
    w = QtHPGLPlotter()
    files = [f for f in argv[1:] if os.path.isfile(f)]
    files.sort(cmp=str_num_cmp)
    w.openFiles(files)
    w.show()
    a.exec_()
        
if __name__ == '__main__':
    main()
