import copy
import datetime
import json
import random
import numpy
import spade


def get_json_from_spade_message(msg):
    return json.loads(msg.body)


def get_spade_message(sender_jid, receiver_jid, body):
    msg = spade.message.Message(to=receiver_jid)
    body["sender"] = str(sender_jid)
    msg.metadata["type"] = body["type"]
    msg.metadata["performative"] = body["performative"]
    msg.body = json.dumps(body)
    return msg


class colorChecker(spade.agent.Agent):
    def __init__(self, jid, password, location, connections):
        super().__init__(jid, password, verify_security=False)
        self.location = location
        self.connections = connections
        self.msgRCount = 0
        self.msgSCount = 0
        self.prevColor = -1
        self.myColor = numpy.random.normal(1, 3)
        self.redList = []
        self.greenList = []
        self.blueList = []
    
    @property
    def connCount(self):
        return len(self.connections)
    
    def setup(self):
        self.add_behaviour(self.hello())
        changeColor_template = spade.template.Template()
        changeColor_template.set_metadata("type", "broadcast")
        changeColor_template.set_metadata("performative", "Inform")
        self.add_behaviour(self.changeColor(), changeColor_template)
    
    class hello(spade.behaviour.OneShotBehaviour):
        async def send_color(self):
            send = { "type": "broadcast", "performative": "Inform", "colorFrom": 0.0, "colorTo": 0.0, }
            send["colorTo"] = self.agent.myColor
            send["colorFrom"] = self.agent.prevColor
            for receiver in self.agent.connections:
                await self.send(get_spade_message(self.agent.jid, receiver, send))
                self.agent.msgSCount += 1
        
        async def run(self):
            await self.send_color()
    
    class changeColor(spade.behaviour.CyclicBehaviour):
        def change_color(self, rcv):
            if rcv["colorTo"] == self.agent.myColor:
                self.agent.prevColor = self.agent.myColor
                self.agent.myColor += 1
                if self.agent.myColor > 3:
                    self.agent.myColor = 1
            if rcv["colorFrom"] == 1:
                if rcv["sender"] in self.agent.redList: self.agent.redList.remove(rcv["sender"])
            if rcv["colorFrom"] == 2:
                if rcv["sender"] in self.agent.greenList: self.agent.greenList.remove(rcv["sender"])
            if rcv["colorFrom"] == 3:
                if rcv["sender"] in self.agent.blueList: self.agent.blueList.remove(rcv["sender"])
            if rcv["colorTo"] == 1:
                if rcv["sender"] not in self.agent.redList: self.agent.redList.append(rcv["sender"])
            if rcv["colorTo"] == 2:
                if rcv["sender"] not in self.agent.greenList: self.agent.greenList.append(rcv["sender"])
            if rcv["colorTo"] == 3:
                if rcv["sender"] not in self.agent.blueList: self.agent.blueList.append(rcv["sender"])
        
        async def send_color(self, rcv):
            send = { "type": "broadcast", "performative": "Inform", "colorFrom": 0.0, "colorTo": 0.0, }
            red_len = 0
            blue_len = 0
            green_len = 0
            red_len = len(self.agent.redList)
            green_len = len(self.agent.greenList)
            blue_len = len(self.agent.blueList)
            flag = 0
            if self.agent.myColor == 1:
                if red_len == 0:
                    flag = 1
            if self.agent.myColor == 2:
                if green_len == 0:
                    flag = 1
            if self.agent.myColor == 3:
                if blue_len == 0:
                    flag = 1
            if flag == 0:
                send["colorFrom"] = self.agent.prevColor
                send["colorTo"] = self.agent.myColor
                for receiver in self.agent.connections:
                    await self.send(get_spade_message(self.agent.jid, receiver, send))
                    self.agent.msgSCount += 1
        
        async def run(self):
            rcv = await self.receive(timeout=10)
            if rcv:
                rcv = get_json_from_spade_message(rcv)
                self.agent.msgRCount += 1
                self.change_color(rcv)
                await self.send_color(rcv)
    
