#!/usr/bin/env python
#
# A port of the semaphore example from Qt.


import sys

# Check if thread support was enabled.
try:
    from qt import QThread
except:
    print "Thread support not enabled"
    sys.exit(1)

from qt import *


# The semaphore instances.
yellowSem = None
greenSem = None


class YellowThread(QThread):
    def __init__(self,o):
        QThread.__init__(self)

        self.receiver = o
        self.stopped = 0
        self.mutex = QMutex()

    def run(self):
        global yellowSem, greenSem

        for i in range(20):
            yellowSem += 1

            event = QCustomEvent(12345)
            event.setData(QString("Yellow!"))
            QThread.postEvent(self.receiver,event)
            self.msleep(200);

            greenSem -= 1

            self.mutex.lock()
            if self.stopped:
                self.stopped = 0
                self.mutex.unlock()
                break

            self.mutex.unlock()

        yellowSem += 1

        event = QCustomEvent(12346)
        event.setData(QString("Yellow!"))
        QThread.postEvent(self.receiver,event)

        greenSem -= 1

    def stop(self):
        self.mutex.lock()
        self.stopped = 1
        self.mutex.unlock()


class GreenThread(QThread):
    def __init__(self,o):
        QThread.__init__(self)

        self.receiver = o
        self.stopped = 0
        self.mutex = QMutex()

    def run(self):
        global yellowSem, greenSem

        for i in range(20):
            greenSem += 1

            event = QCustomEvent(12345)
            event.setData(QString("Green!"))
            QThread.postEvent(self.receiver,event)
            self.msleep(200)

            yellowSem -= 1

            self.mutex.lock()
            if self.stopped:
                self.stopped = 0
                self.mutex.unlock()
                break

            self.mutex.unlock()

        greenSem += 1

        event = QCustomEvent(12346)
        event.setData(QString("Green!"))
        QThread.postEvent(self.receiver,event)
        self.msleep(10)

        yellowSem -= 1

    def stop(self):
        self.mutex.lock()
        self.stopped = 1
        self.mutex.unlock()


class SemaphoreExample(QWidget):
    def __init__(self):
        QWidget.__init__(self)

        self.yellowThread = YellowThread(self)
        self.greenThread = GreenThread(self)

        global yellowSem, greenSem
        yellowSem = QSemaphore(1)
        greenSem = QSemaphore(1)

        self.button = QPushButton("&Ignition!",self)
        self.connect(self.button,SIGNAL("clicked()"),self.startExample)

        self.mlineedit = QMultiLineEdit(self)
        self.label = QLabel(self)

        vbox = QVBoxLayout(self,5)
        vbox.addWidget(self.button)
        vbox.addWidget(self.mlineedit)
        vbox.addWidget(self.label)

    def __del__(self):
        stopYellow = self.yellowThread.running()
        stopGreen = self.greenThread.running()

        if stopYellow:
            self.yellowThread.stop()

        if self.greenThread.running():
            self.greenThread.stop()

        if stopYellow:
            self.yellowThread.wait()

        if stopGreen:
            self.greenThread.wait()

        global yellowSem, greenSem
        yellowSem = None
        greenSem = None

    def startExample(self):
        if self.yellowThread.running() or self.greenThread.running():
            QMessageBox.information(self,"Sorry",
                "The threads have not completed yet, and must finish before "
                "they can be started again.")

            return

        self.mlineedit.clear()

        global yellowSem

        while yellowSem.available() < yellowSem.total():
            yellowSem -= 1

        yellowSem += 1

        self.yellowThread.start()
        self.greenThread.start()

    def customEvent(self,event):
        if event.type() == 12345:
            s = event.data()

            self.mlineedit.append(s)

            if s.latin1() == "Green!":
                self.label.setBackgroundColor(Qt.green)
            else:
                self.label.setBackgroundColor(Qt.yellow)

            self.label.setText(s)

            del s
        elif event.type() == 12346:
            s = event.data()

            QMessageBox.information(self,s.latin1() + " - Finished",
                "The thread creating the \"" + s.latin1() +
                "\" events has finished.")

            del s
        else:
            print "Unknown custom event type:", event.type()


app = QApplication(sys.argv)
se = SemaphoreExample()
app.setMainWidget(se)
se.show()

sys.exit(app.exec_loop())
