from servers.base import BaseServer

import types
import gevent
import importlib
import sys
from optparse import OptionParser

BSERVER_VERSION = "0.1"

class BServerModule:

	def __init__(self, streamservers, greenlets, internals, bserver_mod):
		self.streamservers = streamservers
		self.greenlets = greenlets
		self.bserver_mod = bserver_mod
		self.internals = internals

	def first_internal(self):
		return self.internals[0]

	def join_greenlets(self):
		for greenlet in self.greenlets:
			greenlet.join()

class BServer:

	def __init__(self):
		self.servers = {}
		self.modules = {}

	def start_server(self, module, port, args):
		res = module.start(port, args)

		def recur_item(item):
			if isinstance(item, tuple) or isinstance(item, list):
				items = []
				for child in item:
					items += recur_item(child)
				return items
			else:
				return [item]

		subitems = recur_item(res)
		streamservers = []
		greenlets = []
		internals = []

		for item in subitems:

			if isinstance(item, gevent.server.StreamServer):
				streamservers += [item]
			elif isinstance(item, gevent.greenlet.Greenlet):
				greenlets += [item]
			else:
				internals += [item]

		server = BServerModule(streamservers, greenlets, internals, module)
		self.servers[port] = server
		print("%s started on port %d" % (module.__class__.__name__, port))

	def scan_modules(self):
		subpath = "servers"

		try:
			module = __import__(subpath, globals(), locals(), [subpath.split('.')[-1]])
		except ImportError:
			return

		for name in dir(module):
			mod = getattr(module, name)

			if type(mod) == types.ModuleType:
				submodule = __import__(subpath + "." + name, globals(), locals(), [name])
				for diritem in submodule.__dict__:
					dictitem = submodule.__dict__[diritem]
					#print(str(dictitem))
					if isinstance(dictitem, (types.TypeType, types.ClassType)):
						for base in dictitem.__bases__:
							if base == BaseServer:
								print("Importing server with name " + name + ", type:'" + str(dictitem) + "'")
								self.modules[name] = dictitem
								break

	def join_greenlets(self):
		for port in self.servers:
			self.servers[port].join_greenlets()

def main(argv):
	op = OptionParser(
		version=BSERVER_VERSION,
		description="BServer is a modular gevent BotnetServer")
	print("BServer-v%s - multi-server functionality" % (BSERVER_VERSION))
	
	bserv = BServer()
	bserv.scan_modules()
	loadable_modules = ', '.join(bserv.modules.keys())
	print("Loadable modules: %s" % (loadable_modules))
	modules = []
	for module in bserv.modules:
		op.add_option(
			"--%s" % module,
			action="store_true",
			help="enable the %s module" % module)
		op.add_option(
			"--%s-port" % module,
			metavar="X",
			help="set the port for the %s module" % module, default=0)
		op.add_option(
			"--%s-args" % module,
			metavar="X",
			help="set the space delimited args for the %s module" % module, default="")

	(options, args) = op.parse_args(argv[1:])

	for module in bserv.modules:
		if options.__dict__[module]:
			mod = bserv.modules[module](bserv)
			port = mod.default_port()
			args = mod.default_args().split(" ")

			try:
				port2 = int(options.__dict__[module + "_port"])
				if port2 != 0:
					port = port2
				args2 = options.__dict__[module + "_args"].split(" ")
				if len(args2) > 1 or (len(args2)==1 and args2[0] != '')	:
					args = args2
			except:
				print("Error parsing for %s module" % module)
				continue

			if port == 0:
				print("Error: Port not set for module %s" % module)
				op.print_help()
				continue

			if len(args) == 0:
				print("No args for module %s" % module)
				print("Usage: %s\nDefault args: %s" % (mod.usage(), mod.default_args()))
				print("")
				op.print_help()
				continue

			bserv.start_server(mod, port, args)

	#serv = IRCServer(bserv)
	#serv2 = TFTPServer(bserv)
	#bserv.start_server(serv, 443, [])
	#bserv.start_server(serv2, 69, [])

	if len(bserv.servers.keys()) == 0:
		print("No loaded modules were executed!")
		print("Load one with one of the following arguments")
		op.print_help()
		return

	bserv.join_greenlets()

if __name__ == '__main__':
	main(sys.argv)

