from twisted.internet import task

from core.file_manager import FileManager
from utils.utc_date import UtcDate

class ChatServer():
    '''
        Chat server implementation
    '''
    
    def __init__(self, network_path):
        # list of connected clients
        self.clients = []
        
        # initialize the content with the saved file (if existing) corresponding to the network address
        if FileManager.file_exists(network_path):
            self.content = FileManager.file_read(network_path)
        else:
            self.content = []
        
        self.network_path = network_path
        
        # check regularly that all clients are still active
        task_interval_sec = 20.0
        loop_task = task.LoopingCall(self.remove_inactive_clients)
        loop_task.start(task_interval_sec)
        
    # add a new client to the list of connected clients
    def add_client(self, new_client):
        # send the current content to the new client (whether already connected to the chat or not)
        new_client_greetings = self.content
        new_client.send(self.network_path, "INIT_CONTENT", new_client_greetings)

        # send a notification to the new client with the list of currently connected users (except himself)
        new_client_greetings = [UtcDate.utcnow()]
        if len(self.clients) > 0:
            for client in self.clients:
                if client != new_client:
                    new_client_greetings.append(client.username)
        
        new_client.send(self.network_path, "NOTIFICATION_CLIENT_LIST", new_client_greetings)

        # if the client was already connected to this chat, nothing else to do
        if new_client in self.clients:
            return

        # --- case of a client that was not already connected ---
        # send a message to existing clients
        greetings = [UtcDate.utcnow(), new_client.username]
        for client in self.clients:
            client.send(self.network_path, "NOTIFICATION_NEW_CLIENT", greetings)

        self.clients.append(new_client)
    
    # called when a message is received from any of the connected clients
    def receive_message(self, sender_client, message):
        if message.command == "ENTER":
            # a new client asked to enter the room
            self.add_client(sender_client)
            return
        
        if message.command == "LEAVE":
            self.remove_client(sender_client)
            return

        if message.command == "IS_TYPING":
            message.content = sender_client.username
            for client in self.clients:
                client.send_message(message)
            return
        
        # default case : a client added a message to the chat
        # forward the time, username and message to all connected clients
        message.content = [UtcDate.utcnow(), sender_client.username, message.content]
        
        for client in self.clients:
            client.send_message(message)
        
        # add the new message to the chat history
        self.content.append(message.content)

        # save content to disk
        FileManager.file_write(self.network_path, self.content)
    
    def remove_inactive_clients(self):
        for client in self.clients:
            if client.last_message_delay() > 10.0:
                self.remove_client(client)
    
    # remove a client from the list of connected clients
    def remove_client(self, lost_client):
        try:
            self.clients.remove(lost_client)
        except:
            # client already removed
            return
        
        # message to other clients
        notification_to_send = [UtcDate.utcnow(), lost_client.username]
        
        for client in self.clients:
            client.send(self.network_path, "NOTIFICATION_CLIENT_LEFT", notification_to_send)
