""" This module holds the messages for raft to use.

Message -- Base message class

AppendEntries -- Message representing raft append entries.

RequestVote -- Message representing raft request vote.

RequestVoteReponse -- Message for responding to a request vote.

Response -- Response to an append entries message.
"""
import umsgpack
from enum import Enum

class Messages(Enum):
    AppendEntries = 1
    RequestVote = 2
    RequestVoteResponse = 3
    AppendEntriesResponse = 4 

class Message:
    """The base class of all messages used in raft"""
    _type = None

    def __init__(self, sender, data = {}, term = 0):
        self._sender = sender
        self._data = data
        self._term = term

    @property
    def sender(self):
        return self._sender

    @property
    def type(self):
        return self._type

    def serialise(self):
        """Serialises a Message object into a message pack byte array"""
        raise NotImplementedError

    @staticmethod
    def deserialise(message):
        """Deserialises from a byte array into a Message object

        message -- Message to deserialise.

        Returns -- Deserialised message object, None if incorrect input message. 
        """
        m = None
        try:
            m = umsgpack.unpackb(m)
        except:
            print("Could not decode message")
            return m

        m = Message('tbd')
        raise NotImplementedError

    def __eq__(self, other):
        if not isinstance(other, Message):
            return False

        if other.type != self.type:
            return False

        if other._data != self._data:
            return False

        if other._sender != self._sender:
            return False

        return True
        
class AppendEntries(Message):
    _type = "AppendEntries"

    def __init__(self, term, leaderId, prevLogIndex, prevLogTerm, leaderCommit, entries = None):
        self._data["term"] = term
        self._data["leaderId"] = leaderId
        self._data["prevLogIndex"] = prevLogIndex
        self._data["prevLogTerm"] = prevLogTerm
        self._data["entries"] = entries
        self._data["leaderCommit"] = leaderCommit # Leader's commit index.


class RequestVote(Message):
    _type = "RequestVote"

    def __init__(self, term, candidate_id, last_log_index, last_log_term):
        self._data["candidateId"] = candidate_id
        self._data["lastLogIndex"] = last_log_index
        self._data["lastLogTerm"] = last_log_term

    @property
    def candidate_id(self):
        return self._data["candidateId"]

    @property
    def last_log_index(self):
        return self._data["lastLogIndex"]

    @property
    def last_log_term(self):
        return self._data["lastLogTerm"]


class RequestVoteResponse(Message):
    _type = "RequestVoteResponse"

    def __init__(self, term, vote_granted):
        self._data["voteGranted"] = vote_granted

    @property
    def vote_granted(self):
        return self._data["voteGranted"]

class Response(Message):
    _type = "Response"

    def __init__(self, term, success):
        self._data["success"] = success

    @property
    def success(self):
        return self._data["success"]

    