import unittest
import pydim
from dimbrowser import DimBrowser
import time
import threading
import os
import socket

SERVER_NAME="server_test_dimbrowser"
FIRST_SERVICE_NAME="say_hello_service"
SECOND_SERVICE_NAME="say_hi_service"
FIRST_SERVICE_FORMAT = "C"
SECOND_SERVICE_FORMAT = "C"

COMMAND_1_NAME="example-command-1"
COMMAND_1_FORMAT="D"

def get_hostname():
    return socket.getfqdn()


class Server(threading.Thread):
    '''
    Represents a DIM server
    '''
    def __init__(self):
        threading.Thread.__init__(self)
        self.isStopped = False
        self.createSayHelloService()
        self.createSayHiService()
        self.startServer()

    def say_hello_service_callback(self,tag):
        return ("Hello",)

    def say_hi_service_callback(self,tag):
        return("Hi",)

    def createSayHelloService(self):
        self.sayHelloService = pydim.dis_add_service(FIRST_SERVICE_NAME,FIRST_SERVICE_FORMAT,self.say_hello_service_callback,0)
        if not self.sayHelloService:
            #print("%s has not been created" % (FIRST_SERVICE_NAME))
            sys.exit(1)

        #print("service %s has been registered" % FIRST_SERVICE_NAME)
        pydim.dis_update_service(self.sayHelloService)

    def createSayHiService(self):
        self.sayHiService = pydim.dis_add_service(SECOND_SERVICE_NAME,SECOND_SERVICE_FORMAT,self.say_hi_service_callback,0)
        if not self.sayHiService:
            sys.exit(1)

        pydim.dis_update_service(self.sayHiService)

    def example1Callback(value,tag):
        print("%s call received, value = %s" % (COMMAND_1_NAME,value[0]))

    def addExampleCmnd1(self):
        self.exampleCommand1 = pydim.dis_add_cmnd(COMMAND_1_NAME,COMMAND_1_FORMAT,self.example1Callback,1)

    def removeExampleCmnd1(self):
        pydim.dis_remove_service(self.exampleCommand1)

    def startServer(self):
        #print("Starting %s..." % SERVER_NAME)
        pydim.dis_start_serving(SERVER_NAME)
        #print("%s started" % FIRST_SERVICE_NAME)

    def stop(self):
        pydim.dis_remove_service(self.sayHelloService)
        pydim.dis_remove_service(self.sayHiService)
        self.isStopped = True

    def run(self):
        while not self.isStopped:
            pass

class Client(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.isStopped = False

    def stop(self):
        self.isStopped = True

    def firstServiceCallback(self,value):
        pass

    def run(self):
        res1 = pydim.dic_info_service(FIRST_SERVICE_NAME, self.firstServiceCallback)
        while not self.isStopped:
            pass

class DimBrowserTestCase(unittest.TestCase):
    def setUp(self):
        self.dbr = DimBrowser()

    @classmethod
    def setUpClass(cls):
        cls._server = Server()
        cls._server.start()

    @classmethod
    def tearDownClass(cls):
        cls._server.stop()
        del cls._server

    def tearDown(self):
        del self.dbr

    def test_DimBrowser_instanciation(self):
        self.assertNotEqual(self.dbr,None,'DimBrowser is not instanciated')

class DimBrowserGetServicesTestCase(DimBrowserTestCase):
    def test_one_service_returned_by_getServices(self):
        self.assertEqual(self.dbr.getServices(FIRST_SERVICE_NAME),1)

    def test_first_name_of_service_returned_is_correct(self):
        self.dbr.getServices(FIRST_SERVICE_NAME)
        result = next(self.dbr.getNextService())
        self.assertIsNotNone(result)
        self.assertEqual(result[1],FIRST_SERVICE_NAME)
        self.assertEqual(result[2],FIRST_SERVICE_FORMAT)

    def test_0_service_returned_when_no_service_found(self):
        self.assertEqual(self.dbr.getServices("Service_that_doesn_t_exists"),0)

    def test_none_returned_when_no_service_found(self):
        self.dbr.getServices("Service_that_doesn_t_exists")
        result = next(self.dbr.getNextService())
        self.assertEqual(result,None)

    def test_multiple_services_return_when_wildcard(self):
        service_name = "say_h*"
        nb_services = self.dbr.getServices(service_name)
        self.assertGreater(nb_services,1)
        compteur = 0
        for res in self.dbr.getNextService():
            if res != None:
                compteur+=1
        self.assertEqual(compteur,2)

    def test_format_is_correct_say_hello_service(self):
        service_name = FIRST_SERVICE_NAME
        self.dbr.getServices(service_name)
        res  = next(self.dbr.getNextService())
        self.assertEqual(res[2],FIRST_SERVICE_FORMAT)

class DimBrowserGetServersTestCase(DimBrowserTestCase):

    def test_get_servers(self):
        nb_servers = self.dbr.getServers()
        self.assertEqual(nb_servers,2)

    def test_get_next_server_contains_SERVER_NAME_and_node(self):
        self.dbr.getServers()
        contains_server_name_and_node = False
        res = ("",)
        while res is not None and not contains_server_name_and_node:
            if res[0] == SERVER_NAME:
                if res[1] == get_hostname():
                    contains_server_name_and_node = True
            res = next(self.dbr.getNextServer())

        self.assertTrue(contains_server_name_and_node)


class DimBrowserGetServerServicesTestCase(DimBrowserTestCase):

    def test_number_of_services_returned_getServerServices(self):
        nbServices = self.dbr.getServerServices(SERVER_NAME)
        self.assertEqual(nbServices,2 + 5) # 2 created services + 5 default services

    def test_number_of_services_0_when_server_does_not_exists(self):
        nbServices = self.dbr.getServerServices("server_not_exists")
        self.assertEqual(nbServices,0)

    def test_get_next_server_service_returns_none_when_server_does_not_exists(self):
        self.dbr.getServerServices("server_not_exists")
        self.assertIsNone(next(self.dbr.getNextServerService()))

    def test_get_next_server_service_contains_services_created(self):
        service_1_found = False
        service_2_found = False
        self.dbr.getServerServices(SERVER_NAME)
        res = ("","")
        while res is not None and not (service_1_found and service_2_found):
            res = next(self.dbr.getNextServerService())
            if res is not None:
                if res[1] == FIRST_SERVICE_NAME:
                    service_1_found = True
                elif res[1] == SECOND_SERVICE_NAME:
                    service_2_found = True

        self.assertTrue(service_1_found)
        self.assertTrue(service_2_found)

class DimBrowserGetServerClientsTestCase(DimBrowserTestCase):
    '''GetServerClient cannot be tested efficiently'''

    def test_no_client_connected_to_server(self):
        nbClientsConnected = self.dbr.getServerClients(SERVER_NAME)
        self.assertEqual(nbClientsConnected,0)
        self.assertIsNone(next(self.dbr.getNextServerClient()))

    def test_z_client_connected_to_server(self):
        client = Client()
        client.start()
        time.sleep(2) #wait for the DNS to see the client connected
        nbClientsConnected = self.dbr.getServerClients(SERVER_NAME)
        self.assertEqual(nbClientsConnected,1)
        self.assertIsNotNone(next(self.dbr.getNextServerClient()))
        client.stop()

if __name__ == "__main__":
    dns_node = os.getenv("DIM_DNS_NODE")
    #change the value of the DNS node if necessary by adding the line "dns_node = name_of_dns_node"
    if dns_node is not None:
        pydim.dis_set_dns_node(dns_node)

    if not pydim.dis_get_dns_node():
        print("No Dim DNS node found. Please set the environment variable DIM_DNS_NODE")
        sys.exit(1)

    loader = unittest.TestLoader()

    test_suite = unittest.TestSuite()

    test_suite.addTests(loader.loadTestsFromTestCase(DimBrowserGetServicesTestCase))
    test_suite.addTests(loader.loadTestsFromTestCase(DimBrowserGetServersTestCase))
    test_suite.addTests(loader.loadTestsFromTestCase(DimBrowserGetServerServicesTestCase))
    test_suite.addTests(loader.loadTestsFromTestCase(DimBrowserGetServerClientsTestCase))

    unittest.TextTestRunner(verbosity=1).run(test_suite)

'''from dimbrowser import DimBrowser
import sys
if __name__ == '__main__':
    dbr = DimBrowser()

    nbRes = dbr.getServices("example-command*")
    print("nbServices of example-command server = %s" % nbRes)
    for i in range(nbRes):
        print(dbr.getNextService().next())

    nbServers = dbr.getServers()
    print("NbServers = %s" % nbServers)
    for i in range(nbServers):
        print(dbr.getNextServer().next())

    nbServerServices = dbr.getServerServices("example-commands")
    print("NbServerServices of example-commands server %s" % nbServerServices)
    for i in range(nbServerServices-1):
        print(dbr.getNextServerService().next())

    nbClientsConnected = dbr.getServerClients("example-commands")
    print("nbClientsConnected to server-name = %s" % nbClientsConnected)
    for i in range(nbClientsConnected):
        print(dbr.getNextServerClient().next())

    del dbr'''
