import whatap.util.logging_util as logging_util
import whatap.agent.conf.configure as config
import whatap.agent.secure.security_master as secure
import whatap.net.tcpsession as tcpsession
import whatap.net as net
from whatap.pack.pack import Pack
from whatap.io.data_inputx import DataInputX
from whatap.util.date_util import DateUtil as dateutil
import threading, time, Queue
import math

class __Receiver(threading.Thread):
    def __init__(self) :
        threading.Thread.__init__(self, name='__Receiver')
        self.setDaemon(True)
        self.__queue = Queue.Queue()
        self.__timeSynced = False

    def isTimeSynced(self):
        return self.__timeSynced
        
    def run(self):
        #logging_util.debug('receiver.run step -0.1')
        conf = config.GetConfig()
        secuMaster = secure.GetSecurityMaster()
        #logging_util.debug('receiver.run step -1')
        secuMaster.WaitForInit()
        #logging_util.debug('receiver.run step -2')
        secuSession = secure.GetSecuritySession()
        #logging_util.debug('receiver.run step -3')
        while True:
            try:
                #logging_util.debug('receiver.run step -4')
                session = tcpsession.GetTcpSession()
                while not session.isOpen():
                    session = tcpsession.GetTcpSession()
                    time.sleep(1)
                #logging_util.debug('receiver.run step -5')
                try:
                    out = session.Read()
                except Exception, e:
                    logging_util.error("[Receiver] session.Read failed, closing session: %s" % e)
                    session.Close()
                    time.sleep(1)
                    continue
                #print 'receiver incomming pack', out.code
                if out.code == net.NET_TIME_SYNC :
                    in_ = DataInputX(out.data)
                    prevAgentTime = in_.readLong()
                    serverTime = in_.readLong()
                    now = dateutil.now()
                    turnaroundTime = now - prevAgentTime
                    if turnaroundTime < 500 and math.fabs(float(serverTime-now)) > 1000 :
                        dateutil.setServerDelta(dateutil.getServerDelta()+serverTime - now)
                    self.__timeSynced = True
                    continue

                if conf.CypherLevel > 0 :
                    if out.transferKey != secuSession.transferKey :
                        continue
                    secureMask =  net.GetSecureMask(out.code)
                    if secureMask == net.NET_SECURE_HIDE:
                        if secuSession.cypher is not None:
                            out.data = secuSession.cypher.HideLong(out.data)

                    elif secureMask == net.NET_SECURE_CYPHER:
                        if secuSession.cypher is not None:
                            data_len = len(out.data) if out.data is not None else -1
                            try:
                                out.data = secuSession.cypher.Decrypt(out.data)
                            except Exception, ce:
                                logging_util.error(
                                    "[Receiver] Decrypt failed code=%s len=%d block=%s err=%s" %
                                    (out.code, data_len, secuSession.cypher.block, ce))
                                raise
                    else:
                        logging_util.info(
                            "[Receiver] dropping pack with no secure mask code=%s mask=%s len=%s" %
                            (out.code, secureMask, len(out.data) if out.data is not None else -1))
                        out.data = None
                #print 'receiver step -0.1'
                if out.data:
                    p = Pack.toPack(out.data)
                    #print 'receiver step -1'
                    self.__queue.put(p)

                time.sleep(0.001)
            except Exception, e:
                logging_util.logStack(e)
                time.sleep(0.001)

    def get(self):
        return self.__queue.get()

__receiver = __Receiver()
__receiver.start()

def getReceiver():
    global __receiver

    return __receiver
