# -*- coding: utf-8 -*-
import os
import sys
import json
import socket
from time import sleep
from ...kernel.util.HashTable import HashTable
from ...kernel.system.Directory import Directory
from ...kernel.adapter.FileAdapter import FileAdapter
from ...middleware.remote.RemoteAdm import RemoteAdm
from ...middleware.remote.AdmListener import AdmListener

class Adm(object):
    class __Adm:
        def __init__(self):
            self.val = None
            self.conf = None
            self.adapters = HashTable()
            self.agentsTable = HashTable()
            self.containerList = []
            
        def __str__(self):
            return repr(self) + self.val

        def start(self):
            self.startByConf('')

        def startByConf(self, conf):            
            
            if conf == '':
                self.conf = {
                    "user" : "local",
                    "ip" : "localhost",
                    "port" : 8080,
                    "remote" : None     
                }
            else:
                CONF_DIR = conf
                fa = FileAdapter({'alias':'JsonAdapter', 'type': 'JSON', 'path': CONF_DIR})
                fa.setUp()
                param = fa.request()
                self.conf = param['conf']

            if self.conf['remote']:
                remote = self.conf['remote']                
                if remote['mode'] == 'MASTER':
                    self.remoteAdm = RemoteAdm(remote['ip'], remote['port'])
                    self.remoteAdm.start()    
                else:
                    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)                        
                    attempts = remote['attempts']
                    master = remote['master']
                    data = '{"command": "REGISTER", "alias":"' + remote['container_alias'] + '", "ip":"' + remote['ip'] + '", "port":"'+ str(remote['port']) +'"}'
                    for x in range(1, attempts):                        
                        try:                            
                            sock.connect((master['master_ip'], master['master_port']))                            
                            sock.sendall(bytes(data + "\n", "utf-8"))
                            received = str(sock.recv(1024), "utf-8")
                            print("Received: {}".format(received))                                                            
                            if received == 'ACK' + "\n":
                                break
                        except:
                            sleep(1) # 1 second.
                        finally:
                            sock.close()

                    admListener = AdmListener(remote['ip'], remote['port'])
                    admListener.start()
            
        def addAgent(self, agent):
            self.agentsTable[agent.id] = agent
            ip = ''
            port = ''
            if self.conf['remote']:
                remote = self.conf['remote'] 
                ip = remote['ip']
                port = remote['port']
            directory = Directory()
            directory.addAgent({'agent': agent.id, 'ip': ip, 'port' : port})
            if self.conf['remote']:
                remote = self.conf['remote']
                agents = directory.getAgents()
                dto = '{"command":"UPDATE", "agents" : ' + json.dumps(agents, ensure_ascii=False) + '}'                
                if remote['mode'] == 'MASTER':
                    containers = directory.getContainers()                    
                    for ctn in containers:
                        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                        try:                            
                            sock.connect( (ctn['ip'], int(ctn['port'])) )                            
                            sock.sendall(bytes(dto + "\n", "utf-8"))
                        except:
                            pass
                            
                        finally:
                            sock.close()
                else:
                    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)                        
                    attempts = remote['attempts']
                    master = remote['master']                                              
                    try:                            
                        sock.connect((master['master_ip'], master['master_port']))                            
                        sock.sendall(bytes(dto + "\n", "utf-8"))
                    except:
                        sleep(1) # 1 second.
                    finally:
                        sock.close()
            
        def sendEvent(self, agentID, event, data):
            try:
                ag = self.agentsTable[agentID]
                if (ag):
                    ag.sendEvent(event, data)
                    return True
                else:
                    remote = self.conf['remote'] 
                    attempts = remote['attempts']
                    agents = Directory().getAgents()
                    for agent in agents:
                        if agentID == agent['agent']:
                            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                            aux = str(data)
                            aux = aux.replace("\'", "\"")                                                
                            dto = '{"command": "SENDEVENT", "alias":"' + agentID + '", "event":"' + event + '", "data":'+ aux +'}'
                            print('Send::')
                            print(dto)                               
                            for x in range(1, attempts):                        
                                try:                            
                                    sock.connect((agent['ip'], agent['port']))                            
                                    sock.sendall(bytes(dto + "\n", "utf-8"))
                                    received = str(sock.recv(1024), "utf-8")
                                    print("Received: {}".format(received))                                                            
                                    if received == 'ACK' + "\n":
                                        break
                                except:
                                    sleep(1) # 1 second.
                                finally:
                                    sock.close()
                    return True

            except Exception as inst:
                print('Controled exception in Adm: ')
                print(inst)
                return False

        def addAdapter(self, id, adapter):
            self.adapters[id] = adapter

        def getAdapter(self, id):
            return self.adapters[id]

        def getConf(self):
            return self.conf

        def addContainer(self, container):
            self.containerList.append(container)

        def moveAgent(self, agentID, container):
            ag = self.agentsTable[agentID]
            ag.finalize()
            dto = ag.toDTO()
            print (dto)
            containers = Directory().getContainers()
            for ctn in containers:
                if container == ctn['alias']:
                    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                    try:                            
                        sock.connect( (ctn['ip'], int(ctn['port'])) )                            
                        sock.sendall(bytes(dto + "\n", "utf-8"))
                    except:
                        pass
                    finally:
                        sock.close()
                    break    
            self.agentsTable[agentID] = None
            Directory().removeAgent(agentID)

        def setEndPoint(self, agID, socket):
            ag = self.agentsTable[agID]
            ag.setSocket(socket)
        
    instance = None
    def __new__(cls):
        if not Adm.instance:
            Adm.instance = Adm.__Adm()
        return Adm.instance
    def __getattr__(self, name):
        return getattr(self.instance, name)
    def __setattr__(self, name):
        return setattr(self.instance, name)

# -*- coding: utf-8 -*-
import os
import sys
import json
import socket
from time import sleep
from ...kernel.util.HashTable import HashTable
from ...kernel.system.Directory import Directory
from ...kernel.adapter.FileAdapter import FileAdapter
from ...middleware.remote.RemoteAdm import RemoteAdm
from ...middleware.remote.AdmListener import AdmListener

class Adm(object):
    class __Adm:
        def __init__(self):
            self.val = None
            self.conf = None
            self.adapters = HashTable()
            self.agentsTable = HashTable()
            self.containerList = []
            
        def __str__(self):
            return repr(self) + self.val

        def start(self):
            self.startByConf('')

        def startByConf(self, conf):            
            
            if conf == '':
                self.conf = {
                    "user" : "local",
                    "ip" : "localhost",
                    "port" : 8080,
                    "remote" : None     
                }
            else:
                CONF_DIR = conf
                fa = FileAdapter({'alias':'JsonAdapter', 'type': 'JSON', 'path': CONF_DIR})
                fa.setUp()
                param = fa.request()
                self.conf = param['conf']

            if self.conf['remote']:
                remote = self.conf['remote']                
                if remote['mode'] == 'MASTER':
                    self.remoteAdm = RemoteAdm(remote['ip'], remote['port'])
                    self.remoteAdm.start()    
                else:
                    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)                        
                    attempts = remote['attempts']
                    master = remote['master']
                    data = '{"command": "REGISTER", "alias":"' + remote['container_alias'] + '", "ip":"' + remote['ip'] + '", "port":"'+ str(remote['port']) +'"}'
                    for x in range(1, attempts):                        
                        try:                            
                            sock.connect((master['master_ip'], master['master_port']))                            
                            sock.sendall(bytes(data + "\n", "utf-8"))
                            received = str(sock.recv(1024), "utf-8")
                            print("Received: {}".format(received))                                                            
                            if received == 'ACK' + "\n":
                                break
                        except:
                            sleep(1) # 1 second.
                        finally:
                            sock.close()

                    admListener = AdmListener(remote['ip'], remote['port'])
                    admListener.start()
            
        def addAgent(self, agent):
            self.agentsTable[agent.id] = agent
            ip = ''
            port = ''
            if self.conf['remote']:
                remote = self.conf['remote'] 
                ip = remote['ip']
                port = remote['port']
            directory = Directory()
            directory.addAgent({'agent': agent.id, 'ip': ip, 'port' : port})
            if self.conf['remote']:
                remote = self.conf['remote']
                agents = directory.getAgents()
                dto = '{"command":"UPDATE", "agents" : ' + json.dumps(agents, ensure_ascii=False) + '}'                
                if remote['mode'] == 'MASTER':
                    containers = directory.getContainers()                    
                    for ctn in containers:
                        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                        try:                            
                            sock.connect( (ctn['ip'], int(ctn['port'])) )                            
                            sock.sendall(bytes(dto + "\n", "utf-8"))
                        except:
                            pass
                            
                        finally:
                            sock.close()
                else:
                    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)                        
                    attempts = remote['attempts']
                    master = remote['master']                                              
                    try:                            
                        sock.connect((master['master_ip'], master['master_port']))                            
                        sock.sendall(bytes(dto + "\n", "utf-8"))
                    except:
                        sleep(1) # 1 second.
                    finally:
                        sock.close()
            
        def sendEvent(self, agentID, event, data):
            try:
                ag = self.agentsTable[agentID]
                if (ag):
                    ag.sendEvent(event, data)
                    return True
                else:
                    remote = self.conf['remote'] 
                    attempts = remote['attempts']
                    agents = Directory().getAgents()
                    for agent in agents:
                        if agentID == agent['agent']:
                            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                            aux = str(data)
                            aux = aux.replace("\'", "\"")                                                
                            dto = '{"command": "SENDEVENT", "alias":"' + agentID + '", "event":"' + event + '", "data":'+ aux +'}'
                            print('Send::')
                            print(dto)                               
                            for x in range(1, attempts):                        
                                try:                            
                                    sock.connect((agent['ip'], agent['port']))                            
                                    sock.sendall(bytes(dto + "\n", "utf-8"))
                                    received = str(sock.recv(1024), "utf-8")
                                    print("Received: {}".format(received))                                                            
                                    if received == 'ACK' + "\n":
                                        break
                                except:
                                    sleep(1) # 1 second.
                                finally:
                                    sock.close()
                    return True

            except Exception as inst:
                print('Controled exception in Adm: ')
                print(inst)
                return False

        def addAdapter(self, id, adapter):
            self.adapters[id] = adapter

        def getAdapter(self, id):
            return self.adapters[id]

        def getConf(self):
            return self.conf

        def addContainer(self, container):
            self.containerList.append(container)

        def moveAgent(self, agentID, container):
            ag = self.agentsTable[agentID]
            ag.finalize()
            dto = ag.toDTO()
            print (dto)
            containers = Directory().getContainers()
            for ctn in containers:
                if container == ctn['alias']:
                    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                    try:                            
                        sock.connect( (ctn['ip'], int(ctn['port'])) )                            
                        sock.sendall(bytes(dto + "\n", "utf-8"))
                    except:
                        pass
                    finally:
                        sock.close()
                    break    
            self.agentsTable[agentID] = None
            Directory().removeAgent(agentID)

        def setEndPoint(self, agID, socket):
            ag = self.agentsTable[agID]
            ag.setSocket(socket)
        
    instance = None
    def __new__(cls):
        if not Adm.instance:
            Adm.instance = Adm.__Adm()
        return Adm.instance
    def __getattr__(self, name):
        return getattr(self.instance, name)
    def __setattr__(self, name):
        return setattr(self.instance, name)

# -*- coding: utf-8 -*- # 1 second. # 1 second. # 1 second.