import proxybus
import time
import threading
import sys

debug = False
class ProxyBusDriver(object):
    injectable_errors= ()

    def __init__(self):
        self.name= 'Abstract Bus Driver'
        self.t= None
        self.mutex = threading.Lock()
        self.stopRequest= True
        self.usclockperiod = pow(2,32) - 1
        self.icdxmlfile = proxybus.__proxy_icdxmlfile__

        proxybus.setStartCallback(proxybus.__proxy_identifier__,self.start)
        proxybus.setStopCallback(proxybus.__proxy_identifier__,self.stop)
        proxybus.setSendCallback(proxybus.__proxy_identifier__,self.send)
        proxybus.setUsClockPeriodCallback(proxybus.__proxy_identifier__,lambda : int(self.usclockperiod))
        proxybus.setOnErrorInjectionListCallback(proxybus.__proxy_identifier__,lambda : (self.injectable_errors))

    __del__ = lambda self: None

    def start(self):
        print self.name, "start...",
        if not self.open_comm(): return False
        print self.name, "thread start...",
        self.clean()
        if self.t is not None and self.t.is_alive():
            self.raiseError('when running! thread id=%d'%self.t.ident,3)
        else:
            self.stopRequest= False
            self.t= threading.Thread(name=self.name, target=self._backgroundLoop) #, args=(self,))
            self.t.start()
            print 'new thread id=', self.t.ident
        return self.t.is_alive()

    def stop(self):
        print self.name, "stop..."
        self.acquireLock()
        self.stopRequest= True
        self.releaseLock()
        return True

    def clean(self):
        self.acquireLock()
        if self.t is not None and self.t.is_alive():
            print 'thread id=', self.t.ident, self.t.is_alive(),
            self.t.join(1.0)
            if self.t.is_alive():
                print 'busy'
                self.raiseError("Unable to join python thread...",3)
            else:
                print 'Ok'
        else:
            print 'but no thread alive'  
        self.releaseLock()

    def raiseError(self,msg,severiy):
        proxybus.onBusError(proxybus.__proxy_identifier__,str(msg),int(severiy))

    def forward_msg(self, m_id, m_data):
        proxybus.onReceive(proxybus.__proxy_identifier__,m_id,m_data)

    def acquireLock(self):
        ret =False
        if self.mutex:
            ret= self.mutex.acquire(False)
        return ret

    def releaseLock(self):
        if self.mutex:
            self.mutex.release()

    def _backgroundLoop(self):
        sleep_time = (self.usclockperiod/1000000.0)
        #print self.usclockperiod,sleep_time
        while True:
            begin=time.time()
            if self.acquireLock():
                try:
                    self.iteration()
                except:
                    self.raiseError(sys.exc_info(),3)
                    print self.name, 'error, thread id=', self.t.ident, 'exiting',sys.exc_info()
                    break
                finally:
                    self.releaseLock()
            if self.stopRequest: break
            end = time.time()
            if debug is True : print (end - begin)
            dif = sleep_time - (end - begin)
            if dif > 0 : time.sleep(sleep_time)
            proxybus.onClock(proxybus.__proxy_identifier__)

        print 'closing connection....'
        self.close_comm()

    def send(self, m_id, m_data, m_err):
        return False

    def open_comm(self):
        return False

    def close_comm(self):
        pass

    def iteration(self):
        pass
