## BugCore
##
## Provides a top-level Game that manages the Mods and their Options.
##
## TODO
##   - Fix syntax error in _createParameterizedAccessorPair()
##
## Copyright (c) 2008 The BUG Mod.
##
## Author: EmperorFool

import BugOptions
import BugUtil


## Game and Mods

class Game(object):
	"""Manages a set of Mods."""
	
	def __init__(self):
		self._mods = {}
		self._emptyMods = {}
		self._screens = {}
		self._inited = False
	
	def _createMod(self, id):
		if self._inited:
			raise BugUtil.ConfigError("cannot create mod '%s' after initialization" % id)
		else:
			return self._newMod(id)
	
	def _newMod(self, id):
		mod = Mod(id)
		self._emptyMods[id] = mod
		self._mods[id] = mod
		return mod
	
	def _getMod(self, id):
		if id in self._mods:
			return self._mods[id]
		elif not self._inited:
			BugUtil.info("BugCore - creating uninitialized mod %s", id)
			return self._newMod(id)
		else:
			BugUtil.error("BugCore - invalid mod %s", id)
	
	def _addMod(self, mod):
		id = mod._getID()
		if self._inited:
			BugUtil.warn("BugCore - cannot add mod %s post-init", id)
		elif id in self._emptyMods:
			if not mod._inited:
				BugUtil.error("BugCore - mod %s not initialized", id)
			del self._emptyMods[id]
		elif id in self._mods:
			BugUtil.error("BugCore - mod %s already exists", id)
		else:
			self._mods[id] = mod
	
	def _removeMod(self, id):
		if id in self._mods:
			del self._mods[id]
	
	def _initDone(self):
		if self._inited:
			BugUtil.warn("BugCore - game already initialized")
		else:
			for mod in self._emptyMods.values():
				id = mod._getID()
				if mod._inited:
					BugUtil.warn("BugCore - mod %s not added; adding", id)
					del self._emptyMods[id]
				else:
					BugUtil.warn("BugCore - mod %s not initialized; removing", id)
					self._removeMod(id)
			self._inited = True
	
	def __getattr__(self, id):
		"""Returns the Mod with the given ID."""
		if not id.startswith("_"):
			mod = self._getMod(id)
			if mod is not None:
				return mod
		raise AttributeError(id)
	
	def _getScreen(self, id):
		return self._screens[id]
	
	def _addScreen(self, screen):
		self._screens[screen.id] = screen


class Mod(object):
	"""Provides Option accessors."""
	
	def __init__(self, id):
		self._id = id
		self._options = {}
		self._inited = False
	
	def _getID(self):
		return self._id
	
	def qualify(self, id):
		return BugOptions.qualify(self._id, id)
	
	def _addOption(self, option):
		self._options[option.getID()] = option
	
	def _hasOption(self, id):
		return self.qualify(id) in self._options
	
	def _getOption(self, id):
		try:
			return self._options[self.qualify(id)]
		except KeyError:
			raise BugUtil.ConfigError("Option %s not found in mod %s", id, self._id)
	
	def _initDone(self):
		if self._inited:
			BugUtil.warn("BugCore - mod already initialized")
		else:
			self._inited = True
	
	def __getattr__(self, id):
		"""Returns the Option with the given ID or False for is/getters
		and None for setters that don't exist."""
		if not id.startswith("_"):
			# Try bare option
			if self._hasOption(id):
				return self._getOption(id)
			# If not yet initialized, return False for getters and setters
			if not self._inited:
				if id.startswith("get") or id.startswith("is"):
					return lambda *ignored: False
				if id.startswith("set"):
					return lambda *ignored: False
		raise AttributeError(id)
	
	
	def _createParameterizedAccessorPair(self, id, getter=None, setter=None, values=None):
		id = BugOptions.qualify(self._id, id)
		if getter:
			if values is None:
				def get(*args):
					option = self._getOption(id % args)
					if option.isColor():
						return option.getColor()
					else:
						return option.getValue()
			else:
				def get(*args):
					option = self._getOption(id % args)
					return option.getValue() in values
			setattr(self, getter, get)
		
		if setter:
			def set(value, *args):
				option = self._getOption(id % args)
				option.setValue(value)
			setattr(self, setter, set)


game = Game()

def initDone():
	game._initDone()
