# Path: subspace/node.py
# class Node:
#     def __init__(self, id, ip=None, port=None):
#         self.id = id
#         self.ip = ip
#         self.port = port
#         self.long_id = long(id.encode('hex'), 16)
# 
#     def sameHomeAs(self, node):
#         return self.ip == node.ip and self.port == node.port
# 
#     def distanceTo(self, node):
#         """
#         Get the distance between this node and another.
#         """
#         return self.long_id ^ node.long_id
# 
#     def __iter__(self):
#         """
#         Enables use of Node as a tuple - i.e., tuple(node) works.
#         """
#         return iter([self.id, self.ip, self.port])
# 
#     def __repr__(self):
#         return repr([self.long_id, self.ip, self.port])
# 
#     def __str__(self):
#         return "%s:%s" % (self.ip, str(self.port))
# 
# Path: subspace/routing.py
# class RoutingTable(object):
#     def __init__(self, protocol, ksize, node):
#         """
#         @param node: The node that represents this server.  It won't
#         be added to the routing table, but will be needed later to
#         determine which buckets to split or not.
#         """
#         self.node = node
#         self.protocol = protocol
#         self.ksize = ksize
#         self.flush()
# 
#     def flush(self):
#         self.buckets = [KBucket(0, 2 ** 256, self.ksize)]
# 
#     def splitBucket(self, index):
#         one, two = self.buckets[index].split()
#         self.buckets[index] = one
#         self.buckets.insert(index + 1, two)
# 
#     def getLonelyBuckets(self):
#         """
#         Get all of the buckets that haven't been updated in over
#         an hour.
#         """
#         return [b for b in self.buckets if b.lastUpdated < (time.time() - 3600)]
# 
#     def removeContact(self, node):
#         index = self.getBucketFor(node)
#         self.buckets[index].removeNode(node)
# 
#     def isNewNode(self, node):
#         index = self.getBucketFor(node)
#         return self.buckets[index].isNewNode(node)
# 
#     def addContact(self, node):
#         index = self.getBucketFor(node)
#         bucket = self.buckets[index]
# 
#         # this will succeed unless the bucket is full
#         if bucket.addNode(node):
#             return
# 
#         # Per section 4.2 of paper, split if the bucket has the node in its range
#         # or if the depth is not congruent to 0 mod 5
#         if bucket.hasInRange(self.node) or bucket.depth() % 5 != 0:
#             self.splitBucket(index)
#             self.addContact(node)
#         else:
#             self.protocol.callPing(bucket.head())
# 
#     def getBucketFor(self, node):
#         """
#         Get the index of the bucket that the given node would fall into.
#         """
#         for index, bucket in enumerate(self.buckets):
#             if node.long_id < bucket.range[1]:
#                 return index
# 
#     def findNeighbors(self, node, k=None, exclude=None):
#         k = k or self.ksize
#         nodes = []
#         for neighbor in TableTraverser(self, node):
#             if neighbor.id != node.id and (exclude is None or not neighbor.sameHomeAs(exclude)):
#                 heapq.heappush(nodes, (node.distanceTo(neighbor), neighbor))
#             if len(nodes) == k:
#                 break
# 
#         return map(operator.itemgetter(1), heapq.nsmallest(k, nodes))


import random
import hashlib
from struct import pack
from subspace.node import Node
from subspace.routing import RoutingTable
"""
Utility functions for tests.
"""



def mknode(id=None, ip=None, port=None, intid=None):
    """
    Make a node.  Created a random id if not specified.
    """
    if intid is not None:
        id = pack('>l', intid)
    id = id or hashlib.sha1(str(random.getrandbits(255))).digest()
    return Node(id, ip, port)


class FakeProtocol(object):
    def __init__(self, sourceID, ksize=20):

# Path: subspace/node.py
# class Node:
#     def __init__(self, id, ip=None, port=None):
#         self.id = id
#         self.ip = ip
#         self.port = port
#         self.long_id = long(id.encode('hex'), 16)
# 
#     def sameHomeAs(self, node):
#         return self.ip == node.ip and self.port == node.port
# 
#     def distanceTo(self, node):
#         """
#         Get the distance between this node and another.
#         """
#         return self.long_id ^ node.long_id
# 
#     def __iter__(self):
#         """
#         Enables use of Node as a tuple - i.e., tuple(node) works.
#         """
#         return iter([self.id, self.ip, self.port])
# 
#     def __repr__(self):
#         return repr([self.long_id, self.ip, self.port])
# 
#     def __str__(self):
#         return "%s:%s" % (self.ip, str(self.port))
# 
# Path: subspace/routing.py
# class RoutingTable(object):
#     def __init__(self, protocol, ksize, node):
#         """
#         @param node: The node that represents this server.  It won't
#         be added to the routing table, but will be needed later to
#         determine which buckets to split or not.
#         """
#         self.node = node
#         self.protocol = protocol
#         self.ksize = ksize
#         self.flush()
# 
#     def flush(self):
#         self.buckets = [KBucket(0, 2 ** 256, self.ksize)]
# 
#     def splitBucket(self, index):
#         one, two = self.buckets[index].split()
#         self.buckets[index] = one
#         self.buckets.insert(index + 1, two)
# 
#     def getLonelyBuckets(self):
#         """
#         Get all of the buckets that haven't been updated in over
#         an hour.
#         """
#         return [b for b in self.buckets if b.lastUpdated < (time.time() - 3600)]
# 
#     def removeContact(self, node):
#         index = self.getBucketFor(node)
#         self.buckets[index].removeNode(node)
# 
#     def isNewNode(self, node):
#         index = self.getBucketFor(node)
#         return self.buckets[index].isNewNode(node)
# 
#     def addContact(self, node):
#         index = self.getBucketFor(node)
#         bucket = self.buckets[index]
# 
#         # this will succeed unless the bucket is full
#         if bucket.addNode(node):
#             return
# 
#         # Per section 4.2 of paper, split if the bucket has the node in its range
#         # or if the depth is not congruent to 0 mod 5
#         if bucket.hasInRange(self.node) or bucket.depth() % 5 != 0:
#             self.splitBucket(index)
#             self.addContact(node)
#         else:
#             self.protocol.callPing(bucket.head())
# 
#     def getBucketFor(self, node):
#         """
#         Get the index of the bucket that the given node would fall into.
#         """
#         for index, bucket in enumerate(self.buckets):
#             if node.long_id < bucket.range[1]:
#                 return index
# 
#     def findNeighbors(self, node, k=None, exclude=None):
#         k = k or self.ksize
#         nodes = []
#         for neighbor in TableTraverser(self, node):
#             if neighbor.id != node.id and (exclude is None or not neighbor.sameHomeAs(exclude)):
#                 heapq.heappush(nodes, (node.distanceTo(neighbor), neighbor))
#             if len(nodes) == k:
#                 break
# 
#         return map(operator.itemgetter(1), heapq.nsmallest(k, nodes))


# Path: subspace/tests/utils.py
import random
import hashlib
from struct import pack
from subspace.node import Node
from subspace.routing import RoutingTable

"""
Utility functions for tests.
"""



def mknode(id=None, ip=None, port=None, intid=None):
    """
    Make a node.  Created a random id if not specified.
    """
    if intid is not None:
        id = pack('>l', intid)
    id = id or hashlib.sha1(str(random.getrandbits(255))).digest()
    return Node(id, ip, port)


class FakeProtocol(object):
    def __init__(self, sourceID, ksize=20):

        self.router = RoutingTable(self, ksize, Node(sourceID))