"""!
@package scatt_plot.gthreading

Classes:

(C) 2013 by the GRASS Development Team

This program is free software under the GNU General Public License
(>=v2). Read the file COPYING that comes with GRASS for details.

@author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
"""

import os
import sys
import time
import threading
import Queue

import wx
from core.gconsole import wxCmdRun, wxCmdDone, wxCmdPrepare

class gThread(threading.Thread):
    """!Thread for GRASS commands"""
    requestId = 0

    def __init__(self, receiver, requestQ=None, resultQ=None, **kwds):
        """!
        @param receiver event receiver (used in PostEvent)
        """
        threading.Thread.__init__(self, **kwds)

        if requestQ is None:
            self.requestQ = Queue.Queue()
        else:
            self.requestQ = requestQ

        if resultQ is None:
            self.resultQ = Queue.Queue()
        else:
            self.resultQ = resultQ

        self.setDaemon(True)

        self.receiver = receiver
        self._want_abort_all = False

        self.start()

    def Run(self, *args, **kwds):
        """!Run command in queue

        @param args unnamed command arguments
        @param kwds named command arguments

        @return request id in queue
        """
        gThread.requestId += 1
        self.requestQ.put((gThread.requestId, args, kwds))

        return gThread.requestId

    def GetId(self):
         """!Get id for next command"""
         return gThread.requestId + 1

    def SetId(self, id):
        """!Set starting id"""
        gThread.requestId = id

    def run(self):
        os.environ['GRASS_MESSAGE_FORMAT'] = 'gui'
        while True:
            requestId, args, kwds = self.requestQ.get()
            for key in ('callable', 'onDone', 'onPrepare', 'userData'):
                if key in kwds:
                    vars()[key] = kwds[key]
                    del kwds[key]
                else:
                    vars()[key] = None

            requestTime = time.time()

            #if self._want_abort_all and self.requestCmd is not None:
            #    self.requestCmd.abort()
            #    if self.requestQ.empty():
            #        self._want_abort_all = False

            # prepare
            if self.receiver:
                event = wxCmdPrepare(type = 'method',
                                     time=requestTime,
                                     pid=requestId)

                wx.PostEvent(self.receiver, event)

                # run command
                event = wxCmdRun(type = 'method',
                                 pid=requestId)

                wx.PostEvent(self.receiver, event)

            time.sleep(.1)

            ret = None
            exception = None
            #try:
            ret = vars()['callable'](*args, **kwds)
            #except Exception as e:
            #    exception  = e;

            self.resultQ.put((requestId, ret))

            time.sleep(.1)

          
            if self.receiver:
                event = wxCmdDone(type = 'cmd',
                                  kwds = kwds,
                                  args = args, #TODO expand args to kwds
                                  ret=ret,
                                  exception=exception,
                                  pid=requestId)

                # send event
                wx.PostEvent(self.receiver, event)

    def abort(self, abortall=True):
        """!Abort command(s)"""
        if abortall:
            self._want_abort_all = True
        if self.requestQ.empty():
            self._want_abort_all = False