#!/usr/bin/env python

from twisted.internet import reactor, protocol
from base64 import b64encode, b64decode
import random

class BaseMeshNode(protocol.ProcessProtocol):
  delimiter = '\n'
  __buffer = ''

  def __init__(self, name):
    self.name = name
    self.process = reactor.spawnProcess(self,
                    "test-r-multicast-transport-io",
                    ("test-r-multicast-transport-io", name))

  def sendPacket(self, data):
    "Should be overridden"
    print "Should send: " + data

  def gotOutput(self, data):
    "Should be overridden"
    print "Output: " + data

  def recvPacket(self, data):
    self.process.write("RECV:" + b64encode(data) + "\n")

  def pushInput(self, data):
    self.process.write("INPUT:" + b64encode(data) + "\n")

  def lineReceived(self, line):
    commands = { "SEND"  :  self.sendPacket,
                 "OUTPUT":  self.gotOutput }

    parts = line.rstrip().split(":", 1)
    command = parts[0]
    rawdata = parts[1]
    commands[command](b64decode(rawdata))

  def outReceived(self, data):
    lines = (self.__buffer + data).split(self.delimiter)
    self.__buffer = lines.pop(-1)
    for line in lines:
      self.lineReceived(line)

  def errReceived(self, data):
    print "Error: " + data

  def processEnded(self, reason):
    print "process ended"

class MeshNode(BaseMeshNode):
  def __init__(self, name, mesh):
    BaseMeshNode.__init__(self, name)
    self.mesh = mesh

  def sendPacket(self, data):
    self.mesh.sendPacket(self, data)

  def gotOutput(self, data):
    self.mesh.gotOutput(self, data)

class Link:
  def __init__(self, target, bandwidth, latency, dropchance):
    self.target = target
    self.bandwidth = bandwidth
    self.latency = latency
    self.dropchance = dropchance

  def send(self, data):
    if random.random() > self.dropchance:
      self.target.recvPacket(data)

class Mesh:
  nodes = []
  connections = {};

  def gotOutput(self, node, data):
    print "Got " + data + " from " + node.name

  def connect(self, node0, node1, bandwidth, latency, dropchance):
    self.connections.setdefault(node0, []).append(
       Link(node1, bandwidth, latency, dropchance))

  def connect_full(self, bandwidth, latency, dropchance):
    self.connections = {}
    for x in self.nodes:
      for y in self.nodes:
        if x != y:
          self.connect(x, y, bandwidth, latency, dropchance)

  def sendPacket(self, node, data):
    conn = self.connections.get(node, [])
    for link in conn:
      link.send(data)

  def addNode(self, name):
    node = MeshNode(name, self)
    self.nodes.append(node)
    return node


@@ -316,16 +316,18 @@
        %22
+./
 test-r-m
@@ -409,16 +409,43 @@
 %22, name)
+, %0A                    None
 )%0A%0A  def

Inherit the environment from the parent