## BugDll
##
## Collection of utility functions for dealing with the optional BUG DLL.
##
## General
##
##   - isPresent()
##     Returns True if the BUG DLL is present.
##
##   - getVersion()
##     Returns the version number of the BUG DLL if it's present, zero (0) otherwise.
##
##   - isVersion(version)
##     Returns True if the BUG DLL is present and is version <version> or later.
##
## Widgets
##
##   - widget(bugWidget, bugData1=None, bugData2=None, *args)
##     Returns a tuple of arguments for passing to a function that takes a WidgetTypes and parameters.
##     Chooses between two sets of widgets and parameters based on the presence of the BUG DLL.
##
##   - widgetVersion(version, bugWidget, bugData1=None, bugData2=None, *args)
##     Same as widget() but also checks the BUG DLL version as per isVersion().
##
##   - isWidget(widget, bugWidget)
##     Returns True if <bugWidget> exists and matches <widget>
##
##   - isWidgetVersion(version, widget, bugWidget)
##     Same as isWidget() but also checks the BUG DLL version as per isVersion().
##
## Notes
##   - Must be initialized externally by calling init()
##
## Copyright (c) 2009 The BUG Mod.
##
## Author: EmperorFool

from CvPythonExtensions import *
import BugOptions
import BugUtil

gc = CyGlobalContext()

IS_PRESENT = False
VERSION = -1


## General and Versions

def isBug():
	return True

def isPresent():
	return IS_PRESENT

def getVersion():
	return VERSION

def isVersion(version):
	if version > 0:
		return IS_PRESENT and VERSION >= version
	else:
		return IS_PRESENT

def decode(value, noneIsZero=False):
	if value:
		if isinstance(value, int):
			if value >= 1:
				return value
		else:
			try:
				version = int(value)
				if version >= 1:
					return version
			except ValueError:
				pass
	if noneIsZero:
		return 0
	else:
		return None


## Widgets

def widget(bugWidget, bugData1=None, bugData2=None, *args):
	return widgetVersion(VERSION, bugWidget, bugData1, bugData2, *args)

def widgetVersion(version, bugWidget, bugData1=None, bugData2=None, *args):
	"""
	Picks one of two WidgetTypes and parameters to return based on presence of BUG DLL and <version>.
	
	The bugWidget must be the name of the desired widget, e.g. "WIDGET_SET_PERCENT";
	the other widget should be the WidgetTypes constant, e.g. WidgetTypes.WIDGET_CHANGE_PERCENT.
	
	The default widget values are WidgetTypes.WIDGET_GENERAL, -1, -1. To specify a different set,
	pass them in as the 4th, 5th and 6th arguments.
	
	To return zero or one data values, pass None for the BUG values you want not to have returned;
	the same ones won't be returned if the BUG DLL isn't present. When overriding the non-BUG widget
	type, you must always pass in three values: the WidgetTypes and its two data values. The matching
	BUG ones that are None will not be returned, regardless of their own values.
	
	Any arguments after the widget arguments are added at the end of the returned tuple; use this
	when the function you are passing the arguments to takes more arguments after the widget values.
	
	Make sure to use a * to unpack the returned tuple when passing the arguments to your function.
	
	Example:
		screen.setButtonGFC( "MinCommerceRate", u"", "", 130, 50, 20, 20, 
							 *BugDll.widget("WIDGET_SET_PERCENT", eCommerce, 0, 
							 				WidgetTypes.WIDGET_CHANGE_PERCENT, eCommerce, -100, 
							 				ButtonStyles.BUTTON_STYLE_CITY_MINUS) )
	"""
	realArgs = []
	if len(args) >= 3 and isinstance(args[0], WidgetTypes):
		normalWidget, normalData1, normalData2 = args[:3]
		args = args[3:]
	else:
		normalWidget=WidgetTypes.WIDGET_GENERAL
		normalData1=-1
		normalData2=-1
	handled = False
	if isVersion(version):
		try:
			if isinstance(bugWidget, WidgetTypes):
				realArgs.append(bugWidget)
			else:
				realArgs.append(getattr(WidgetTypes, bugWidget))
			if bugData1 is not None:
				realArgs.append(bugData1)
			if bugData2 is not None:
				realArgs.append(bugData2)
			handled = True
		except AttributeError:
			BugUtil.warn("WidgetTypes.%s not found", bugWidget)
	if not handled:
		realArgs.append(normalWidget)
		if bugData1 is not None:
			realArgs.append(normalData1)
		if bugData2 is not None:
			realArgs.append(normalData2)
	if args:
		realArgs.extend(args)
	return realArgs


def isWidget(widget, bugWidget):
	return isWidgetVersion(VERSION, widget, bugWidget)

def isWidgetVersion(version, widget, bugWidget):
	"""
	Returns True if <widget> has the same value as <bugWidget>, False otherwise.
	
	If the BUG DLL isn't present, doesn't have the correct version, or the widget
	doesn't exist, False is safely returned.
	"""
	if isVersion(version):
		try:
			return widget == getattr(WidgetTypes, bugWidget)
		except:
			pass
	return False


## Accessing Options

def getOptionBOOL(argsList):
	return castOptionValue(bool, *argsList)

def getOptionINT(argsList):
	return castOptionValue(int, *argsList)

def getOptionFLOAT(argsList):
	return castOptionValue(float, *argsList)

def getOptionSTRING(argsList):
	return castOptionValue(str, *argsList)

def castOptionValue(func, id, default):
	try:
		return func(BugOptions.getOption(id).getValue())
	except:
		return default


def init():
	"""
	Checks for the presence of the BUG DLL and grabs its Python API version if found.
	"""
	try:
		if gc.isBull():
			global IS_PRESENT, VERSION
			IS_PRESENT = True
			VERSION = gc.getBullApiVersion()
			BugUtil.info("BugDll - %s %s, API version %d", gc.getBullName(), gc.getBullVersion(), VERSION)
			if hasattr(CyGlobalContext, "setIsBug"):
				import BugInit
				BugInit.addInit("setIsBug", setIsBug)
			else:
				BugUtil.debug("BugDll - setIsBug() not found")
	except:
		BugUtil.debug("BugDll - BULL not present")

def setIsBug():
	"""
	Tells BULL that BUG is ready to receive queries for options.
	"""
	BugUtil.debug("BugDll - calling setIsBug()")
	gc.setIsBug(True)
