# -*- coding: utf-8 -*-
from twisted.internet.protocol import DatagramProtocol
from c2w.main.lossy_transport import LossyTransport

import logging
import frame
import logic
import ctypes
import struct
import time

from c2w.main.user import c2wUser
from c2w.main.user import c2wUserStore
from c2w.main.movie import c2wMovie
from c2w.main.movie import c2wMovieStore
from c2w.main.server_proxy import c2wServerProxy

from twisted.internet import reactor

logging.basicConfig()
moduleLogger = logging.getLogger('c2w.protocol.udp_chat_server_protocol')


class c2wUdpChatServerProtocol(DatagramProtocol):
    
    def __init__(self, serverProxy, lossPr):
        """
        :param serverProxy: The serverProxy, which the protocol must use
            to interact with the user and movie store (i.e., the list of users
            and movies) in the server.
        :param lossPr: The packet loss probability for outgoing packets.  Do
            not modify this value!

        Class implementing the UDP version of the client protocol.

        .. note::
            You must write the implementation of this class.

        Each instance must have at least the following attribute:

        .. attribute:: serverProxy

            The serverProxy, which the protocol must use
            to interact with the user and movie store in the server.

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

        .. note::
            You must add attributes and methods to this class in order
            to have a working and complete implementation of the c2w
            protocol.
        """
	    ################ global variables ######################
        self.sequenceNumber=0
        self.userList = []
        # retrieve the current user information
        self.utilisateur = c2wUser(None,None,None,None) 
        self.UserMaxNumber = 255
	
        self.ReturnMainRoom = False
        self.MovieOpen = [False, 0]
        self.flag_broadcast = [False,0]	# by default roomId is 0 for main-room
        self.sequenceNumber = {}
    
        self.timer_List = {}
        self.timer_counter_List = {}	#if it exceeds num_limit, stop!! 
        self.timer_num_limit = 3
    
        # to pass the test there must be a delay less than 2
        self.delay = 2		
	
        ################ system variables ################
	self.serverProxy = serverProxy
        self.lossPr = lossPr
	self.userStore = c2wUserStore()

    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

    def datagramReceived(self, datagram, (host, port)):
        """
        :param string datagram: the payload of the UDP packet.
        :param host: the IP address of the source.
        :param port: the source port.

        Called **by Twisted** when the server has received a UDP
        packet.
        """
        print "----------------SERVER Receive data----------------------------"
        Frame_receive = logic.logic.binaryToObject(datagram)
	
        #-----Receive request and return an ACK-------------------------------"
	if Frame_receive.ack == 0:	                  #it needs an ACK
            print "-----------------Receive a request no ACK----------------------"
	    print "Received Message Type : "+ str(Frame_receive.msgType)
	    print "Received Message Data : "+ str(Frame_receive.data)
	    
	    """
	    Here, self is used to call ackFunDict
	    This is the reason we will then visually establish self
	    The sequence number of the ACK always equals the sent frame
	    """
	    #**********************Login request***********************************
	    if Frame_receive.msgType == int('0000', 2):
		self.ACK_Login(Frame_receive, (host, port))
		
	    #**********************Leave to Main Room Request**********************
	    elif (Frame_receive.msgType == int('1000', 2)) & (Frame_receive.roomType == 00):
		print "*********************Leave to Main Room Request**********************"
		self.ACK_LeaveToMainRoom(Frame_receive, (host, port))
	    
	    #**********************Room Request--Movie Room************************
	    elif (Frame_receive.msgType == int('1000', 2)) & (Frame_receive.roomType == 01):
		print "*********************Movie Room Request**********************"
		self.ACK_RoomRequest(Frame_receive, (host, port))
		
	    #**********************Room Request--Private Room**********************
	    elif (Frame_receive.msgType == int('1000', 2)) & (Frame_receive.roomType == 02):
		print "*********************Private Room Request**********************"
		self.timer_counter_List[Frame_receive.userId] = 0
		self.Forward_PrivateChat_sign(Frame_receive)
		
	    #**********************Private Message send****************************
	    elif Frame_receive.msgType == int('0001',2) | Frame_receive.roomType == 2:
		print "********************* Private Message send**********************"
		self.ACK_PrivateChat_msg(Frame_receive, (host, port))
		
	    #**********************Broadcast Room Message send*********************
	    elif Frame_receive.msgType == int('0001',2) | Frame_receive.roomType != 2:
		print "*********************Broadcast Room Message send**********************"
                self.ACK_RoomChatMessage(Frame_receive, (host, port))
		self.BroadCast_Message(Frame_receive)
		
	    #**********************Message send************************************
	    elif Frame_receive.msgType == int('1111',2):
		print "*********************Disconnection Request**********************"
		self.ACK_Disconnection(Frame_receive, (host, port))
	    
	else:
	    print "-----------------------Receive an ACK and response------------------------------"
	    print "Received Message Type : "+ str(Frame_receive.msgType)
	    print "Received Message Data : "+ str(Frame_receive.data)
	    
	    
	    # ***************after Movie List ACK**********************************
	    if Frame_receive.msgType == int('0011', 2):
		print "********************after Movie List ACK**********************************"
		print "increment the seq num!!!"
		self.sequenceNumber[Frame_receive.userId] += 1
		print "ACK MovieList sequenceNumber: "+str(self.sequenceNumber[Frame_receive.userId])
		self.timer_List[Frame_receive.userId].cancel()
		
		self.timer_counter_List[Frame_receive.userId] = 0
		self.sendUserList(Frame_receive.userId, (host, port), 0) # 0 is main-room

	    # **************after User List ACK************************************	
	    elif Frame_receive.msgType == int('0101', 2):
		print "********************after User List ACK**********************************"
		print "increment the seq num!!!"
		self.sequenceNumber[Frame_receive.userId] += 1
		print "ACK UserList sequenceNumber: "+str(self.sequenceNumber[Frame_receive.userId])
		self.timer_List[Frame_receive.userId].cancel()
		
		if self.MovieOpen[0] :
		    MovieInstance = self.serverProxy.getMovieById(self.MovieOpen[1])
		    self.serverProxy.startStreamingMovie(MovieInstance.movieTitle)
                print "flag_broadcast" + str(self.flag_broadcast[0])
            
		if self.flag_broadcast[0] == True:
		    print "begin the broadcast"
            
            # flag_broadcast[1] is roomId for userlist        
		    self.BroadCast_UserList(Frame_receive.userId, self.flag_broadcast[1])	
		    
		    if self.MovieOpen[0]:
			self.BroadCast_UserList(Frame_receive.userId, 0)	
                    
                    print "ReturnMainRoom" + str(self.ReturnMainRoom)  
                    if self.ReturnMainRoom:
			self.BroadCast_UserList(Frame_receive.userId, 0)	
			
		    self.flag_broadcast[0] = False
		    self.flag_broadcast[1] = 0
		    
                self.MovieOpen = [False, 0]
                self.ReturnMainRoom = False
                    
		    
	    elif Frame_receive.msgType == int('1010', 2):
		print "********************after signalisation PrivateChat ACK**********************************"
		print "increment the seq num!!!"
		self.sequenceNumber[Frame_receive.userId] += 1
		print "ACK UserList sequenceNumber: "+str(self.sequenceNumber[Frame_receive.userId])
		
		self.timer_List[Frame_receive.userId].cancel()
		self.ACK_PrivateChat_sign(Frame_receive)
		
	    elif Frame_receive.msgType == int('1100', 2):
		print "********************after message PrivateChat ACK**********************************"
		print "increment the seq num!!!"
		self.sequenceNumber[Frame_receive.userId] += 1
		print "ACK UserList sequenceNumber: "+str(self.sequenceNumber[Frame_receive.userId])
		
		self.timer_List[Frame_receive.userId].cancel()
		
	    elif Frame_receive.msgType == int('0001', 2):
		print "********************after send-msg to destinataire ACK**********************************"
		print "increment the seq num!!!"
		self.sequenceNumber[Frame_receive.userId] += 1
		print "ACK UserList sequenceNumber: "+str(self.sequenceNumber[Frame_receive.userId])
		
		self.timer_List[Frame_receive.userId].cancel()
    
    def ACK_Login(self, Frame_receive, (host, port)):
        """
        :param Frame_receive: the payload after processing by binaryToObject
                              in logic.py
        :param host: the IP address of the source.
        :param port: the source port.
        
        called for the first ACK sent to the client
        """    
   	print "----------------------ACK Login-------------------------"
	ack = 1			        # change the value of ack to 1
	""" change the value of roomType to 11(binary)/3(decimal) 
	 except Chat messages and user lists, all the others should be made 11
	"""
	roomType = 3
	# usually the ACK frame is too short to be cut, so it's always 0		
	fragment = 0
	# except Movie Room User list, Message broadcasted to a room, Private message, the others must be		    
	destinationId = 0		 
	
	flag = self.serverProxy.getUserByName(Frame_receive.data)
	
	if flag == None:    
	    sequenceNumber = Frame_receive.sequenceNumber
	    msgType = Frame_receive.msgType 
	    #print "distribution of New userId in condition of LoginIn et creation de l'utiisateur"
	    userId = self.serverProxy.addUser(Frame_receive.data, "MAIN_ROOM", None ,(host, port)) # add the new user to the list
	    print ' the new userId is '+ str(userId)
	    self.sequenceNumber[userId] = 0
	    # List of userStore
	    self.userStore.createAndAddUser(Frame_receive.data, "MAIN_ROOM",None,None,userId)
	    self.flag_broadcast[0] = True
	    self.flag_broadcast[1] = 0
	    
	    dataLength = 0		# in case of ACK, it's thought as zero
	
	    Frame_send = frame.frame(fragment, ack, msgType, roomType, sequenceNumber, userId, destinationId, dataLength)
	    self.transport.write(logic.logic.ObjectToBinary(Frame_send), (host, port))
	    
	    # 2  l'envoi de Movie List
	    self.timer_counter_List[userId] = 0
	    self.sendMovieList(userId, (host, port))
	    
	elif Frame_receive.sequenceNumber == 0:			# First ACK of Login is lost and resend the this ack
	    sequenceNumber = Frame_receive.sequenceNumber
	    msgType = Frame_receive.msgType 
	    #print "distribution of New userId in condition of LoginIn et creation de l'utiisateur"
	    userId = flag.userId
	    print ' the new userId is '+ str(userId)
	    self.sequenceNumber[userId]=0
	    # List of userStore
	    #self.userStore.createAndAddUser(Frame_receive.data, "MAIN_ROOM",None,None,userId)
	    #self.flag_broadcast[0] = True
	    #self.flag_broadcast[1] = 0
	    
	    dataLength = 0		# in case of ACK, it's thought as zero
	    Frame_send = frame.frame(fragment, ack, msgType, roomType, sequenceNumber, userId, destinationId, dataLength)
	    self.transport.write(logic.logic.ObjectToBinary(Frame_send), (host, port))
	    
	    # 2  l'envoi de Movie List
	    self.timer_List[userId].cancel()
	    self.timer_counter_List[userId] = 0
	    self.sendMovieList(userId, (host, port))
	else:
	    sequenceNumber = 0			#  duplicate the UserName error
	    msgType = 14			#  error messageType
	    dataLength = 1
	    data = 6	# Invalid Message
	    Frame_send = frame.frame(fragment, ack, msgType, roomType,
	                             sequenceNumber, Frame_receive.userId+1,
	                             destinationId, dataLength, data)
	    self.transport.write(logic.logic.ObjectToBinary(Frame_send), (host, port))
    
    def ACK_Disconnection(self,Frame_receive, (host, port)):
        """
        :param Frame_receive: the payload after processing by binaryToObject
                              in logic.py
        :param host: the IP address of the source.
        :param port: the source port.
        
        called by datagramReceived when it receives a msgType 1111 Disconnection Request
        """ 

        ack = 1				 # change the value of ack to 1
        """ change the value of roomType to 11(binary)/3(decimal) 
            except Chat messages and user lists, all the others should be made 11
        """
        roomType = 3	               
        fragment = 0		 # usually the ACK frame is too short to be cut, so it's always 0
    
        for user in self.serverProxy.getUserList():
               if user.userId == Frame_receive.userId:
                   name_update = user.userName
                   break
            
        self.serverProxy.removeUser(name_update)
    
        #self.serverProxy.updateUserChatroom(name_update, "OUT_OF_THE_SYSTEM_ROOM")
        self.userStore.updateUserChatRoom(name_update, "OUT_OF_THE_SYSTEM_ROOM")
    
        sequenceNumber = Frame_receive.sequenceNumber
        msgType = Frame_receive.msgType
        userId = Frame_receive.userId
        destinationId = 0
        dataLength = 0
        Frame_send = frame.frame(fragment, ack, msgType, roomType,
                             sequenceNumber, userId, destinationId, dataLength)
        self.transport.write(logic.logic.ObjectToBinary(Frame_send), (host, port))
       
        print "begin the broadcast"
        self.BroadCast_UserList(Frame_receive.userId, 0)	# BroadCast MainRoom,   '' represent for BroadCast everyOne
	
    
	
    def ACK_RoomRequest(self, Frame_receive, (host, port)):
        """
        :param Frame_receive: the payload after processing by binaryToObject
                              in logic.py
        :param host: the IP address of the source.
        :param port: the source port.
        
        called by datagramReceived when it receives a msgType 1000 Movie Room Request
               and the roomType is 02
        """ 
        # 1  premier ACK destine au client
        print "----------------------ACK RoomRequest-------------------------"
        ack = 1			    # change the value of ack to 1
        """ change the value of roomType to 11(binary)/3(decimal) 
            except Chat messages and user lists, all the others should be made 11
        """
        roomType = 3	       
        fragment = 0		# usually the ACK frame is too short to be cut, so it's always 0

        Movie = self.serverProxy.getMovieById(Frame_receive.destinationId)
        print "destinationId"+str(Frame_receive.destinationId)
     
        if Movie == None:
           sequenceNumber = Frame_receive.sequenceNumber
           msgType = 14		#error message  movieNumber is wrong
           destinationId = 0
           dataLength = 1
           data = 6 		# Invalid Message 
           Frame_send = frame.frame(fragment, ack, msgType, roomType, 
                                    sequenceNumber, Frame_receive.userId+1,
                                    destinationId, dataLength, data)
           self.transport.write(logic.logic.ObjectToBinary(Frame_send), (host, port))
        
        else:
           self.MovieOpen = [True,Frame_receive.destinationId]
           #Find the source UserName correspond to UserId in sake of using udateChatroom()
           for user in self.serverProxy.getUserList():
               if user.userId == Frame_receive.userId:
                   name_update = user.userName
                   break
            
           # modify(serverProxy) Room status of User to Movie_Room
           self.serverProxy.updateUserChatroom(name_update, Movie.movieTitle)
           print "userlist mis a jour"+str(self.serverProxy.getUserList())
           # modify(userStore) Ro+om status of User to certain Movie_Room Title
           self.userStore.updateUserChatRoom(name_update, Movie.movieTitle)
           self.flag_broadcast[0] = True
           self.flag_broadcast[1] = Frame_receive.destinationId
        
           sequenceNumber = Frame_receive.sequenceNumber
           msgType = Frame_receive.msgType
        
           #print "distribution of New userId in condition of LoginIn et creation de l'utiisateur"
           userId = Frame_receive.userId
           print 'movieIpAddress '+ str(Movie.movieIpAddress)
           destinationId = Frame_receive.destinationId
           data = [Movie.moviePort, Movie.movieIpAddress]
           dataLength = 2 + len(Movie.movieIpAddress)	# in case of ACK_RoomRequest, it has the content
        
           Frame_send = frame.frame(fragment, ack, msgType, roomType,
                                    sequenceNumber, userId, destinationId,
                                    dataLength, data)
           self.transport.write(logic.logic.ObjectToBinary(Frame_send), (host, port))
        
           # 2  l'envoi de Movie List
           self.timer_counter_List[userId] = 0
           self.sendUserList(userId ,(host, port), destinationId)
        
    def ACK_LeaveToMainRoom(self, Frame_receive, (host, port)):
        """
        :param Frame_receive: the payload after processing by binaryToObject
                              in logic.py
        :param host: the IP address of the source.
        :param port: the source port.
        
        called by datagramReceived when it receives a msgType 1000 Room Request
               and the roomType is 00
        """ 
        print "----------------------ACK_LeaveToMainRoom-------------------------"
        ack = 1			    # change the value of ack to 1
        """ change the value of roomType to 00(binary)/0(decimal) 
            except Chat messages and user lists, all the others should be made 11
        """
        roomType = 0           
        fragment = 0		# usually the ACK frame is too short to be cut, so it's always 0
    
        for user in self.serverProxy.getUserList():
                if user.userId == Frame_receive.userId:
                    name_update = user.userName
                    stopStreamingMovie = user.userChatRoom
                    break
        Movie = self.serverProxy.getMovieByTitle(stopStreamingMovie)
    
        self.flag_broadcast[0] = True
        self.flag_broadcast[1] = Movie.movieId
    
        self.serverProxy.stopStreamingMovie(stopStreamingMovie)
        self.serverProxy.updateUserChatroom(name_update, "MAIN_ROOM")
        self.userStore.updateUserChatRoom(name_update, "MAIN_ROOM")
        sequenceNumber = Frame_receive.sequenceNumber
        msgType = Frame_receive.msgType
        userId = Frame_receive.userId
        destinationId = 0
        dataLength = 0
        Frame_send = frame.frame(fragment, ack, msgType, roomType, sequenceNumber, userId, destinationId, dataLength)
        self.transport.write(logic.logic.ObjectToBinary(Frame_send), (host, port))
    
        # 2  Send the User List
        self.timer_counter_List[userId] = 0
        self.sendUserList(userId ,(host, port), destinationId)
    
        self.ReturnMainRoom = True
	    #print "begin the broadcast"
	    #print "Movie.movieId",Movie.movieId
	    #self.BroadCast_UserList(Frame_receive.userId, Movie.movieId)	    
	
	    #self.BroadCast_UserList('', 0)	# BroadCast MainRoom,   '' represent for BroadCast everyOne
	
    def ACK_RoomChatMessage(self, Frame_receive, (host, port)):
        """
        :param Frame_receive: the payload after processing by binaryToObject
                              in logic.py
        :param host: the IP address of the source.
        :param port: the source port.
        
        called by datagramReceived when it receives a msgType 0001 Message
               or the roomType is not 02
        """ 
        print "----------------------ACK_PrivateChat-------------------------"
        ack = 1			        # change the value of ack to 1
        """ set the roomType to whatever the current room is
        """
        roomType = Frame_receive.roomType
        fragment = 0            # usually the ACK frame is too short to be cut, so it's always 0
        msgType = Frame_receive.msgType           
        sequenceNumber = Frame_receive.sequenceNumber
       
        userId = Frame_receive.userId
        destinationId = Frame_receive.destinationId
        dataLength = 0
        Frame_send = frame.frame(fragment, ack, msgType, roomType,
                                 sequenceNumber, userId, destinationId,
                                 dataLength)
	self.transport.write(logic.logic.ObjectToBinary(Frame_send), (host, port))
        
	    
    def ACK_PrivateChat_sign(self, Frame_receive):
        """
        :param Frame_receive: the payload after processing by binaryToObject
                              in logic.py
        :param host: the IP address of the source.
        :param port: the source port.
        
        called by datagramReceived when it receives a msgType 1010 Private Chat Request
        """ 
        # 1  premier ACK destine au client
        print "----------------------ACK_PrivateChat-------------------------"
        ack = 1		        # change the value of ack to 1
        """ change the value of roomType to 10(binary)/2(decimal) 
            because this is a private chat message
        """
        roomType = 2	
        fragment = 0	    # usually the ACK frame is too short to be cut, so it's always 0

        UserInstance = self.serverProxy.getUserById(Frame_receive.destinationId)
        print "UserInstance"+str(UserInstance)

        sequenceNumber = Frame_receive.sequenceNumber
        msgType = 8
        
        userId = Frame_receive.destinationId
        destinationId = Frame_receive.userId
        dataLength = 0
        
        Frame_send = frame.frame(fragment, ack, msgType, roomType, 
                                 sequenceNumber, userId, destinationId,
                                 dataLength)
        self.transport.write(logic.logic.ObjectToBinary(Frame_send), 
	                         UserInstance.userAddress)
	
    def ACK_PrivateChat_msg(self, Frame_receive, (host, port)):
        """
        :param Frame_receive: the payload after processing by binaryToObject
                              in logic.py
        :param host: the IP address of the source.
        :param port: the source port.
        
        called by datagramReceived when it receives a msgType 0001 Message
               or the roomType is equal to 02 (Private Chat)
        """ 
        
        # 1  premier ACK destine au client
        print "----------------------ACK_PrivateChat-------------------------"
        ack = 1		     # change the value of ack to 1
        """ change the value of roomType to 10(binary)/2(decimal) 
            because this is a private chat message
        """
        roomType = 2	
        fragment = 0	 # usually the ACK frame is too short to be cut, so it's always 0

        sequenceNumber = Frame_receive.sequenceNumber
        msgType = Frame_receive.msgType
        
        userId = Frame_receive.userId
        destinationId = Frame_receive.destinationId
        dataLength = 0
        
        Frame_send = frame.frame(fragment, ack, msgType, roomType,
                                 sequenceNumber, userId, destinationId,
                                 dataLength)
        self.transport.write(logic.logic.ObjectToBinary(Frame_send),
                             (host, port))
    
        self.Forward_PrivateChat_msg(Frame_receive)
	
    
	


    def sendMovieList(self, userId , (host, port)):
        """
        :param userId: the users numerical user id
        :param host: the IP address of the source.
        :param port: the source port.
        
        called by ACK_Login after processing the first ACK sent to the client
        """
        if self.timer_counter_List[userId]< self.timer_num_limit:
        
            print "------------------sending Movie list data to the client--------------------"
            MovieList = self.serverProxy.getMovieList()
            fragment = 0
            ack = 0
            msgType = 3
            """ change the value of roomType to 11(binary)/3(decimal) 
                except Chat messages and user lists, all the others should be made 11
            """
            roomType = 3
            data = []
        
            dataLength = 0
            roomId=0
            for movie in MovieList:
                    nameLength = len(movie.movieTitle)
                    data.append([nameLength, movie.movieId, movie.movieTitle])
                    dataLength = dataLength + 2 + nameLength
            
            Frame_send = frame.frame(fragment, ack, msgType, roomType, 0, userId,
                                     0, dataLength, data)	# sequenceNumber = 0
            self.transport.write(logic.logic.ObjectToBinary(Frame_send),
                                 (host, port))
    
    
            a = reactor.callLater(self.delay, self.sendMovieList, userId, (host, port))
            self.timer_List[userId] = a
            self.timer_counter_List[userId] += 1
    
	
	
	
    def sendUserList(self ,userId ,(host, port), RoomId):
        """
        :param userId: the users numerical user id
        :param host: the IP address of the source.
        :param port: the source port.
        :param RoomId: destinationId.
        
        called by ACK_RoomRequest after updating users room location
        """
        if self.timer_counter_List[userId]< self.timer_num_limit:
            print "------------------sending User list data to the client--------------------"
        
            fragment = 0
            ack = 0
            msgType = 5
         
            if  RoomId == 0:
            
                #UserList = self.userStore.getChatRoomUsersList("MAIN_ROOM")
                    UserList = self.serverProxy.getUserList()
                    destinationId=0
                    roomType = 0   		# at the moment, roomtype is 00 for main room
                    data = []
            
                    dataLength = 0
                    for user in UserList:
                       print "userAddress" + str(user.userAddress)
                       nameLength = len(user.userName)
                       data.append([nameLength, user.userId , user.userChatRoom,  user.userName])
                       dataLength = dataLength + 3 + nameLength
            else:
                Movie= self.serverProxy.getMovieById(RoomId)
                print "MovieIP: "+ Movie.movieIpAddress
                UserList = self.userStore.getChatRoomUsersList(Movie.movieTitle)
                destinationId=RoomId
                roomType = 1   		# at the moment, roomtype is 01 for movie room
                data = []
                dataLength = 0
                for user in UserList:
                    print "user" + str(user)
                    nameLength = len(user.userName)
                    data.append([nameLength, user.userId, user.userChatRoom , user.userName])
                    dataLength = dataLength + 3 + nameLength	

            Frame_send = frame.frame(fragment, ack, msgType, roomType,
                                                self.sequenceNumber[userId], userId,
                                                destinationId, dataLength, data)
            self.transport.write(logic.logic.ObjectToBinary(Frame_send), (host, port))
            a = reactor.callLater(self.delay, self.sendUserList ,userId, (host, port),RoomId)
            self.timer_List[userId] = a
            self.timer_counter_List[userId] += 1
    
    def BroadCast_UserList(self, userId, RoomId):
        """
        :param userId: the users numerical user id
        :param RoomId: flag_broadcast[1].
        
        called by ACK_RoomRequest after updating users room location
        """
	print "------------------Broadcast User list update--------------------"
        UserList = self.serverProxy.getUserList()
        new_userList = []
	
	if RoomId == 0:
	    print "------------------Broadcast User list in main room update--------------------"
	    print "userList: " + str(UserList)
	    if len(UserList) > 1:
		for user in UserList:
		    if (user.userChatRoom == 'MAIN_ROOM') & (user.userId != userId):
			new_userList.append(user)
		    
		print "len MainRoom_BroadCast" + str(new_userList)
		for user in new_userList:
		    self.timer_counter_List[user.userId] = 0
		    self.sendUserList(user.userId ,user.userAddress, RoomId)
	    else:
		print "No BroadCast"
		
	else:	# Movie Room update UserList
	    print "------------------Broadcast User list in movie room update--------------------"
	    print "userList: " + str(UserList)
	    Movie = self.serverProxy.getMovieById(RoomId)	
	    if len(UserList) > 1:
		for user in UserList:
		    if (user.userChatRoom == Movie.movieTitle) & (user.userId != userId):
			new_userList.append(user)
		    
		print "len MovieRoom_BroadCast: " + str(new_userList)
		print "MovieTitle"+ Movie.movieTitle
		for user in new_userList:
		    self.timer_counter_List[user.userId] = 0
		    self.sendUserList(user.userId ,user.userAddress, RoomId)
		
	    else:
		print "No BroadCast"
		
    def Send_msg( self , Frame_receive, finishId):			# msg-type is 0001
        """
        :param userId: the users numerical user id
        :param RoomId: flag_broadcast[1].
        
        called by BroadCast_Message to update UserList
        """
        if self.timer_counter_List[finishId]< self.timer_num_limit:
	    print "----------------------Send_msg one to one-------------------------"
    	    RoomId = Frame_receive.destinationId
	    
	    if RoomId == 0:
	        roomType = 00
	    else:
		roomType = 01
		    
	    fragment = 0
	    UserInstance = self.serverProxy.getUserById(finishId)
	    print "UserInstance"+str(UserInstance)

	    ack = 0
	    msgType = 1  #0001  0x01
	    userId = finishId
	    sequenceNumber = self.sequenceNumber[userId]
	    destinationId = Frame_receive.userId
	    dataLength = Frame_receive.dataLength
	    data = Frame_receive.data
		       
	    Frame_send = frame.frame(fragment, ack, msgType, roomType, sequenceNumber, userId, destinationId, dataLength, data)
	    self.transport.write(logic.logic.ObjectToBinary(Frame_send), UserInstance.userAddress)
	    a = reactor.callLater(self.delay, self.Send_msg, Frame_receive, finishId)
	    self.timer_List[userId] = a
	    self.timer_counter_List[userId] += 1
		
    def BroadCast_Message(self, Frame_receive): 
        """
        :param Frame_receive: the payload after processing by binaryToObject
                              in logic.py
        called by datagramReceived when it receives a msgType 0001 (Message)
               or the roomType is not equal to 02 (Private Chat)
        """ 
	print "------------------Broadcast Message update--------------------"
	UserList = self.serverProxy.getUserList()
	new_userList = []
	RoomId = Frame_receive.destinationId
	userId = Frame_receive.userId
	
	if RoomId == 0:
	    print "userList: " + str(UserList)
	    if len(UserList) > 1:
		for user in UserList:
		    if (user.userChatRoom == 'MAIN_ROOM') & (user.userId != userId):
			new_userList.append(user)
		    
		print "len MainRoom_BroadCast_List" + str(new_userList)
		for user in new_userList:
		    self.timer_counter_List[user.userId] = 0
		    self.Send_msg(Frame_receive, user.userId)
	    else:
		print "No BroadCast"
		
	else:	# Movie Room update UserList
	    print "userList: " + str(UserList)
	    Movie = self.serverProxy.getMovieById(RoomId)	
	    if len(UserList) > 1:
		for user in UserList:
		    if (user.userChatRoom == Movie.movieTitle) & (user.userId != userId):
			new_userList.append(user)
		    
		print "len MovieRoom_BroadCast: " + str(new_userList)
		print "MovieTitle"+ Movie.movieTitle
		for user in new_userList:
		    self.timer_counter_List[user.userId] = 0
		    self.Send_msg(Frame_receive, user.userId)
	    else:
		print "No BroadCast"


	def Forward_PrivateChat_sign(self, Frame_receive):			# msg-type is 1010
	    """
        :param Frame_receive: the payload after processing by binaryToObject
                              in logic.py
        called by datagramReceived when it receives a msgType 1010 (Private Chat request)
        and the roomType is 02 (Private Chat)

        """
	    if self.timer_counter_List[userId]< self.timer_num_limit:
		print "----------------------Forward_PrivateChat-------------------------"
		""" change the value of roomType to 10(binary)/2(decimal) 
	        because this is a private chat message
	    """
		roomType = 2
		fragment = 0
		UserInstance = self.serverProxy.getUserById(Frame_receive.destinationId)
		print "UserInstance"+str(UserInstance)
		ack = 0
		    
		msgType = 10     #1010  0x0a 
		userId = Frame_receive.destinationId
		sequenceNumber = self.sequenceNumber[userId]
		destinationId = Frame_receive.userId
		dataLength = 0
		    
		    
		Frame_send = frame.frame(fragment, ack, msgType, roomType, sequenceNumber, userId, destinationId, dataLength)
		self.transport.write(logic.logic.ObjectToBinary(Frame_send), UserInstance.userAddress)
		a = reactor.callLater(self.delay, self.Forward_PrivateChat, Frame_receive)
		self.timer_List[userId] = a
		self.timer_counter_List[userId] += 1
		
	def Forward_PrivateChat_msg(self, Frame_receive):			# msg-type is 1100
		"""
        :param Frame_receive: the payload after processing by binaryToObject
                              in logic.py
        called by ACK_PrivateChat_msg when it receives a msgType 1100 (Message Forward)
        """
        if self.timer_counter_List[userId]< self.timer_num_limit:
            print "----------------------Forward_PrivateChat-------------------------"
            
            roomType = 2
            fragment = 0
            UserInstance = self.serverProxy.getUserById(Frame_receive.destinationId)
            print "UserInstance"+str(UserInstance)

            ack = 0
            msgType = 12  #1100  0x0c
            userId = Frame_receive.destinationId
            sequenceNumber = self.sequenceNumber[userId]
            destinationId = Frame_receive.userId
            dataLength = Frame_receive.dataLength
            data = Frame_receive.data
                
                
            Frame_send = frame.frame(fragment, ack, msgType, roomType, sequenceNumber, userId, destinationId, dataLength, data)
            self.transport.write(logic.logic.ObjectToBinary(Frame_send), UserInstance.userAddress)
            a = reactor.callLater(self.delay, self.Forward_PrivateChat, Frame_receive)
            self.timer_List[userId] = a
            self.timer_counter_List[userId] += 1
		
	    
		
	
