#!/usr/bin/env python
#
# Zoek de eerste vrije (== niet in een wleiden.conf gedefinieerde) interlink
# range.
#
# Maybe this should use the py-iplib module?
#
# Orignal: lodewijk@wirelessleiden.nl
# 07/March/2012 - Rick van der Zwet <info@rickvanderzwet.nl>
#
import re
import sys
import glob
import gformat

def parseaddr(s):
  f = s.split('.')
  return (long(f[0]) << 24L) + \
    (long(f[1]) << 16L) + \
    (long(f[2]) << 8L) + \
    long(f[3])


def showaddr(a):
  return "%d.%d.%d.%d" % ((a >> 24) & 0xff, (a >> 16) & 0xff, (a >> 8) & 0xff, a & 0xff)


bezet_cache = None
def make_cache():
  global bezet_cache
  bezet = {}
  substs = {}
  def add_ip(address):
    if '/' not in address:
      address += "/32"

    addr, mask = address.split('/')
    if addr in substs:
      addr = substs[addr]
    try:
      addr = parseaddr(addr)
      mask = int(mask)
      addr = addr & ~((1 << (32 - mask)) - 1)
      for i in range(0, (1 << (32 - mask))):
        bezet[addr + i] = 1
    except ValueError, e:
      print "[FOUT] in address %s node %s" % (address, node)
  
  for node in gformat.get_hostlist():
    datadump = gformat.get_yaml(node)

    add_ip(datadump['masterip'])
    for key in datadump['autogen_iface_keys']:
      add_ip(datadump[key]['ip'])

  # Fetching smallest in use IP 
  # XXX: Currently not used for anything
  i = parseaddr("255.255.255.255")
  for k in bezet.keys():
    if k < i:
      i = k
  bezet_cache = bezet
  return bezet


def get_ranges(interlink, size, aantal, use_history=False):
  global bezet_cache
  numaddrs = 1 << (32 - size)
  
  if not use_history or (use_history and not bezet_cache):
    bezet = make_cache()
  else:
    bezet = bezet_cache
  
 
  # Interlinks are living in special ranges usually
  if interlink:
    i = parseaddr("172.16.3.0")
  else:
    i = parseaddr("172.17.0.0")
  
  ranges = []
  for n in xrange(aantal):
    okay = False
    while not okay: 
      while bezet.has_key(i):
        i = i + numaddrs
      
      # Assume Ok, till we find a already used IP
      okay = True
      for j in range(numaddrs):
        if bezet.has_key(i + j):
          i = i + numaddrs
          okay = False
          break
    ranges.append(i)
    bezet[i] = 1

  bezet_cache = bezet
  return ranges



def main():
  if len(sys.argv) < 2:
    print "Gebruik: %s <interlink|subnet> <grootte> [aantal]" % sys.argv[0]
    print "Voorbeelden:"
    print "\tVoor drie /29 interlinks - '%s interlink 29 3'" % sys.argv[0]
    print "\tVoor een (1) /24 subnet  - '%s subnet 24'" % sys.argv[0]
    exit(1)
  
  # Argument parsing
  interlink = sys.argv[1] == 'interlink'
  size = int(sys.argv[2])
  try:
    aantal = int(sys.argv[3])
  except (KeyError,IndexError):
      aantal = 1
  
  ranges = get_ranges(interlink, size, aantal)
  numaddrs = 1 << (32 - size)

  for i in ranges:
    print "%s/%d:" % (showaddr(i), size),
    if size > 28:
      print " en ".join([showaddr(i) for i in range(i + 1, i + numaddrs - 1)])
    else:
      print " en ".join([showaddr(i) for i in range(i + 1, i + 4)]),
      print "...",
      print " en ".join([showaddr(i) for i in range(i + numaddrs - 7, i + numaddrs - 4)])

if __name__ == "__main__":
    main()
