# Copyright 2015-2016 HyperBit developers
import collections
import random
import time
from hyperbit import config, pow, serialize, crypto


class Header(object):
    def __init__(self, magic, command, length, checksum):
        self.magic = magic
        self.command = command
        self.length = length
        self.checksum = checksum

    @classmethod
    def from_bytes(cls, data):
        s = serialize.Deserializer(data)
        magic = s.uint(4)
        command = s.str(12).rstrip('\0')
        length = s.uint(4)
        checksum = s.bytes(4)
        return cls(magic, command, length, checksum)

    def to_bytes(self):
        s = serialize.Serializer()
        s.uint(self.magic, 4)
        s.bytes(bytes(self.command, 'utf8')[:12].ljust(12, b'\0'))
        s.uint(self.length, 4)
        s.bytes(self.checksum)
        return s.data


class Generic(object):
    def __init__(self, command, data):
        self.command = command
        self.data = data


class Version(object):
    def __init__(self, version, services, timestamp, dst_services, dst_ip, dst_port, src_services, src_ip, src_port, nonce, user_agent, streams):
        self.command = 'version'
        self.version = version
        self.services = services
        self.timestamp = timestamp
        self.dst_services = dst_services
        self.dst_ip = dst_ip
        self.dst_port = dst_port
        self.src_services = src_services
        self.src_ip = src_ip
        self.src_port = src_port
        self.nonce = nonce
        self.user_agent = user_agent
        self.streams = streams

    @classmethod
    def from_bytes(cls, data):
        s = serialize.Deserializer(data)
        return cls(
            version=s.uint(4),
            services=s.uint(8),
            timestamp=s.uint(8),
            dst_services=s.uint(8),
            dst_ip=s.bytes(16),
            dst_port=s.uint(2),
            src_services=s.uint(8),
            src_ip=s.bytes(16),
            src_port=s.uint(2),
            nonce=s.uint(8),
            user_agent=s.vstr(),
            streams=[s.vint() for i in range(s.vint())]
        )

    @property
    def data(self):
        t = serialize.Serializer()
        t.uint(self.version, 4)
        t.uint(self.services, 8)
        t.uint(self.timestamp, 8)
        t.uint(self.dst_services, 8)
        t.bytes(self.dst_ip)
        t.uint(self.dst_port, 2)
        t.uint(self.src_services, 8)
        t.bytes(self.src_ip)
        t.uint(self.src_port, 2)
        t.uint(self.nonce, 8)
        t.vstr(self.user_agent)
        t.vint(len(self.streams))
        for stream in self.streams:
            t.vint(stream)
        return t.data