import sys
import json, ast
from RTEInterface import RTEInterface
from kafka import KafkaConsumer
import json

constants_file = open("../../constants_local.json")
constants = json.load(constants_file)
print(constants)
#consumer = KafkaConsumer('deployed', 'removeWorker',
 #                        "request", bootstrap_servers='10.129.6.5:9092')
consumer = KafkaConsumer(constants["topics"]["deployed"], constants["topics"]["remove_worker"],
                         constants["topics"]["request_dm_2_rm"], bootstrap_servers=constants["network"]["external"]["kafka_host"])

RTEInterface.Connect('thrift', "10.129.2.182", 20206)
tableId = "ingress::dispatch"
tableId2 = "ingress::fwd"
ruleDictionary = {}

def makeRule(ip, port, mac, functionHash, tableId, rule_name, default_rule):
    actions = '{  "type" : "ingress::dispatch_act",  "data" : {  "dstAddr" : { "value" : "%s" }, \
        "dstPort" : { "value" : "%d" } , "egress_port": { "value": "p1" }, "ethernetAddr": { "value": "%s" } } }' \
         % (ip, int(port), mac)
    match = '{ "map_hdr.function_id" : {  "value" : %d} }' % (functionHash)
    rule = {
        "tableId": tableId,
        "rule_name": rule_name,
        "default_rule": default_rule,
        "match": match,
        "actions": actions  
    }
    return rule

def addRule(worker):
    functionHash = worker[u'functionHash']
    rule_name = "dispatch_to_worker" + functionHash
    # functionHash = int(functionHash[0:5], 16)
    functionHash = int(functionHash[9:])
    ip = str(worker[u'node_id']).strip()
    port = int(worker[u'portExternal'])
    mac = str(worker[u'mac']).strip()
    default_rule = False
    rule = makeRule(ip, port, mac, functionHash, tableId, rule_name, default_rule)
    ruleDictionary[functionHash] = rule
    print "rule added: ", ruleDictionary
    RTEInterface.Tables.AddRule(
        rule["tableId"], rule["rule_name"], rule["default_rule"], rule["match"], rule["actions"])
    ruleList = RTEInterface.Tables.ListRules(tableId)
    print "new rule list: ", ruleList, "\n\n"
    return 0

def deleteRule(worker):
    functionHash = worker[u'functionHash']
    # functionHash = int(functionHash[0:5], 16)
    functionHash = int(functionHash[9:])
    rule = ruleDictionary[functionHash]
    RTEInterface.Tables.DeleteRule(
        rule["tableId"], rule["rule_name"], rule["default_rule"], rule["match"], rule["actions"])
    del ruleDictionary[functionHash]
    ruleList = RTEInterface.Tables.ListRules(tableId)
    print "deleted rule"
    print "new rule list: ", ruleList, "\n\n"
    
    return 0

def updateDefaultRule(worker):
    # TODO 1: implement function to update deault rule when worker load heap changes
    # def EditRule(self, tbl_id, rule_name, default_rule, match, actions, priority = None, timeout = None):
    rule_name = "default"
    # functionHash = int(functionHash[0:5], 16)
    ip = str(worker[u'node_id']).strip()
    port = int(worker[u'port'])
    mac = str(worker[u'mac']).strip()
    default_rule = True
    rule = makeRule(ip, port, mac, None, tableId, rule_name, default_rule)

    RTEInterface.Tables.EditRule(rule["tableId"], rule["rule_name"], rule["default_rule"], rule["match"], rule["actions"])
    print("\nDefault rule updated\n\n")
    return 0

def makeFwdTableRule(rule_name, default_rule):
    rule={}
    if default_rule:
        actions = '{  "type" : "ingress::fwd_act",  "data" : { "port" : { "value" : "p0" } } }'
        match = '{ "standard_metadata.ingress_port" : {  "value" : "v0.0" } }'
        rule = {
            "tableId": tableId2,
            "rule_name": 'host_to_net',
            "default_rule": default_rule,
            "match": match,
            "actions": actions  
        }
    else:
        actions = '{  "type" : "ingress::fwd_act",  "data" : { "port" : { "value" : "p0" } } }'
        match = '{ "standard_metadata.ingress_port" : {  "value" : "v0.0" } }'
        rule = {
            "tableId": tableId2,
            "rule_name": 'host_to_net',
            "default_rule": default_rule,
            "match": match ,
            "actions": actions  
        }
    return rule

def updateDefaultRule2():
    # TODO 1: implement function to update deault rule when worker load heap changes
    # def EditRule(self, tbl_id, rule_name, default_rule, match, actions, priority = None, timeout = None):

    default_rule = False
    rule_name = 'host_to_net'
    rule = makeRule2(rule_name, default_rule)
    print(rule)
    RTEInterface.Tables.EditRule(rule["tableId"], rule["rule_name"], rule["default_rule"], rule["match"], rule["actions"])

for msg in consumer:
    # print("message received : ", msg)
    if msg.topic == constants["topics"]["deployed"]:
        msg = msg.value.decode('utf-8')
        worker = json.loads(msg)
        print("received message on deployed : ", worker)
        addRule(worker)
    
    elif msg.topic == constants["topics"]["remove_worker"]:
        msg = msg.value.decode('utf-8')
        worker = json.loads(msg)
        print("received message on removeWorker : ", worker)
        deleteRule(worker)

    elif msg.topic == "COLDSTART_WORKER":
        msg = msg.value.decode('utf-8')
        worker = json.loads(msg)
        print("received message on COLDSTART_WORKER : ", worker)
        updateDefaultRule(worker[u'nodes'])

    # elif msg.topic == "AUTOSCALE":
    #     msg = msg.value.decode('utf-8')
        
    
# updateDefaultRule2()

# worker={
#     'node_id': '192.168.2.3',
#     'portExternal': '8081',
#     'mac': '00:22:22:22:22:22'
# }
# updateDefaultRule(worker)