## GPUtil
##
## Utilities for dealing with Great People.
##
## MODDERS
##
##   There are four places where you must add information about your new great people.
##   This is also necessary if you assign GP points to buildings that don't normally get them,
##   for example GG points to Heroic Epic.
##
##	 1. Unit Type
##	 2. Named constant
##	 3. Color
##	 4. Icon (font glyph or string)
##
## Notes
##   - Must be initialized externally by calling init()
##
## Copyright (c) 2007-2009 The BUG Mod.
##
## Author: EmperorFool

from CvPythonExtensions import *
import BugUtil
import FontUtil
import PlayerUtil

gc = CyGlobalContext()

# Generic GP icon
g_gpIcon = None

# Unit Type of each great person that can gain GP points
g_gpBarList = (
	"UNIT_GREAT_SPY",
	"UNIT_ENGINEER",
	"UNIT_MERCHANT",
	"UNIT_SCIENTIST",
	"UNIT_ARTIST",
	"UNIT_PROPHET",
	"UNIT_GREAT_GENERAL",
# MOD: specify the unit type (XML key) for each new great person (1)
#	"UNIT_SLAVE",
)

# Named constants for each great person and total number of GP types
# These must be in the exact same order as the list above
NUM_GP = len(g_gpBarList)
(
	GP_SPY,
	GP_ENGINEER,
	GP_MERCHANT,
	GP_SCIENTIST,
	GP_ARTIST,
	GP_PROPHET,
	GP_GENERAL,
# MOD: define a constant for each new great person in same order as above (2)
#	GP_SLAVE,
) = range(NUM_GP)

# Map each GP type to unit ID, color, and icon to show in GP Bar
g_gpUnitTypes = None
g_gpColors = None
g_unitIcons = None


# Information

def init():
	global g_gpIcon
	g_gpIcon = FontUtil.getChar("greatpeople")
	
	global g_gpUnitTypes
	g_gpUnitTypes = [None] * NUM_GP
	for i, s in enumerate(g_gpBarList):
		g_gpUnitTypes[i] = gc.getInfoTypeForString(s)
	
	global g_gpColors
	g_gpColors = [None] * NUM_GP
	g_gpColors[GP_SPY] = gc.getInfoTypeForString("COLOR_WHITE")
	g_gpColors[GP_ENGINEER] = gc.getYieldInfo(YieldTypes.YIELD_PRODUCTION).getColorType()
	g_gpColors[GP_MERCHANT] = gc.getInfoTypeForString("COLOR_YELLOW")
	g_gpColors[GP_SCIENTIST] = gc.getInfoTypeForString("COLOR_RESEARCH_STORED")
	g_gpColors[GP_ARTIST] = gc.getInfoTypeForString("COLOR_CULTURE_STORED")
	g_gpColors[GP_PROPHET] = gc.getInfoTypeForString("COLOR_BLUE")
	g_gpColors[GP_GENERAL] = gc.getInfoTypeForString("COLOR_RED")
	# MOD: specify color for each new great person (3)
	#g_gpColors[GP_SLAVE] = gc.getInfoTypeForString("COLOR_WHITE")
	
	global g_unitIcons
	g_unitIcons = {}
	g_unitIcons[g_gpUnitTypes[GP_SPY]] = FontUtil.getChar(FontSymbols.COMMERCE_ESPIONAGE_CHAR)
	g_unitIcons[g_gpUnitTypes[GP_ENGINEER]] = FontUtil.getChar(FontSymbols.YIELD_PRODUCTION_CHAR)
	g_unitIcons[g_gpUnitTypes[GP_MERCHANT]] = FontUtil.getChar(FontSymbols.COMMERCE_GOLD_CHAR)
	g_unitIcons[g_gpUnitTypes[GP_SCIENTIST]] = FontUtil.getChar(FontSymbols.COMMERCE_RESEARCH_CHAR)
	g_unitIcons[g_gpUnitTypes[GP_ARTIST]] = FontUtil.getChar(FontSymbols.COMMERCE_CULTURE_CHAR)
	g_unitIcons[g_gpUnitTypes[GP_PROPHET]] = FontUtil.getChar(FontSymbols.RELIGION_CHAR)
	g_unitIcons[g_gpUnitTypes[GP_GENERAL]] = FontUtil.getChar(FontSymbols.GREAT_GENERAL_CHAR)
	# MOD: specify icon (font glyph) for each new great person (4)
	#g_unitIcons[g_gpUnitTypes[GP_SLAVE]] = FontUtil.getChar(FontSymbols.UNHAPPY_CHAR)

def getUnitType(gpType):
	return g_gpUnitTypes[gpType]

def getColor(gpType):
	return g_gpColors[gpType]

def getUnitIcon(iUnit):
	try:
		return g_unitIcons[iUnit]
	except:
		BugUtil.warn("no GP icon for unit %d", iUnit)
		return u"%c" % CyGame().getSymbolID(FontSymbols.GREAT_PEOPLE_CHAR)


# Getting Progress

def getDisplayCity():
	"""
	Returns the city to display in the progress bar.
	"""
	pHeadSelectedCity = CyInterface().getHeadSelectedCity()
	if (pHeadSelectedCity and pHeadSelectedCity.getTeam() == gc.getGame().getActiveTeam()):
		city = pHeadSelectedCity
		iTurns = getCityTurns(city)
	else:
		city, iTurns = findNextCity()
		if not city:
			city, iGPP = findMaxCity()
			iTurns = None
	return (city, iTurns)

def findNextCity():
	iMinTurns = None
	iTurns = 0
	player = gc.getPlayer(gc.getGame().getActivePlayer())
	iThreshold = player.greatPeopleThreshold(False)
	bestCity = None
	for city in PlayerUtil.playerCities(player):
		iRate = city.getGreatPeopleRate()
		if (iRate > 0):
			iProgress = city.getGreatPeopleProgress()
			iTurns = (iThreshold - iProgress + iRate - 1) / iRate
			if (iMinTurns is None or iTurns < iMinTurns):
				iMinTurns = iTurns
				bestCity = city
	return (bestCity, iMinTurns)

def findMaxCity():
	iMaxProgress = 0
	player = gc.getPlayer(gc.getGame().getActivePlayer())
	bestCity = None
	for city in PlayerUtil.playerCities(player):
		iProgress = city.getGreatPeopleProgress()
		if (iProgress > iMaxProgress):
			iMaxProgress = iProgress
			bestCity = city
	return (bestCity, iMaxProgress)

def getCityTurns(city):
	if (city):
		player = gc.getPlayer(city.getOwner())
		iThreshold = player.greatPeopleThreshold(False)
		iRate = city.getGreatPeopleRate()
		if (iRate > 0):
			iProgress = city.getGreatPeopleProgress()
			iTurns = (iThreshold - iProgress + iRate - 1) / iRate
			return iTurns
	return None

def calcPercentages(city):
	# Calc total rate
	iTotal = 0
	if not g_gpUnitTypes is None:
		for iUnit in g_gpUnitTypes:
			iTotal += city.getGreatPeopleUnitProgress(iUnit)
	# Calc individual percentages based on rates and total
	percents = []
	if (iTotal > 0):
		iLeftover = 100
		for iUnit in range(gc.getNumUnitInfos()):
#			iUnit = getUnitType(gpType)
			iProgress = city.getGreatPeopleUnitProgress(iUnit)
			if (iProgress > 0):
				iPercent = 100 * iProgress / iTotal
				iLeftover -= iPercent
				percents.append((iPercent, iUnit))
		# Add remaining from 100 to first in list to match Civ4
		if (iLeftover > 0):
			percents[0] = (percents[0][0] + iLeftover, percents[0][1])
	return percents


# Displaying Progress

def getHoverText(eWidgetType, iData1, iData2, bOption):
	city, iTurns = getDisplayCity()
	if (not city):
		# no rate or progress in any city and no city selected
		return BugUtil.getText("TXT_KEY_MISC_GREAT_PERSON", (0, PlayerUtil.getActivePlayer().greatPeopleThreshold(False)))
	iThreshold = gc.getPlayer(city.getOwner()).greatPeopleThreshold(False)
	iProgress = city.getGreatPeopleProgress()
	iRate = city.getGreatPeopleRate()
	szText = BugUtil.colorText(city.getName(), "COLOR_HIGHLIGHT_TEXT")
	szText += u"\n"
	szText += BugUtil.getText("TXT_KEY_MISC_GREAT_PERSON", (iProgress, iThreshold))
	if (iRate > 0):
		szText += u"\n%d%s%s " % (iRate, g_gpIcon, BugUtil.getPlainText("TXT_KEY_PER_TURN"))
		szText += BugUtil.getText("INTERFACE_CITY_TURNS", (iTurns,))
	
	percents = calcPercentages(city)
	if (len(percents) > 0):
		percents.sort()
		percents.reverse()
		szText += u"\n"
		for iPercent, iUnit in percents:
#			iUnit = getUnitType(gpType)
			szText += u"\n%s%s - %d%%" % (getUnitIcon(iUnit), gc.getUnitInfo(iUnit).getDescription(), iPercent)
	return szText

def getGreatPeopleText(city, iGPTurns, iGPBarWidth, bGPBarTypesNone, bGPBarTypesOne, bIncludeCityName):
	sGreatPeopleChar = u"%c" % CyGame().getSymbolID(FontSymbols.GREAT_PEOPLE_CHAR)
	iGreatPeopleCreated = 0
	if gc.getGame().getActivePlayer() != -1: 
		if gc.getPlayer(gc.getGame().getActivePlayer()).getGreatPeopleCreated() > 0:
			iGreatPeopleCreated = gc.getPlayer(gc.getGame().getActivePlayer()).getGreatPeopleCreated()
	sNextGP = str(iGreatPeopleCreated + 1)

	if (not city):
		szText = BugUtil.getText("INTERFACE_GREAT_PERSON_NONE", (sGreatPeopleChar, ))
	elif (bGPBarTypesNone):
		sGP = sNextGP + ". " + sGreatPeopleChar
		if (iGPTurns):
			if (bIncludeCityName):
				szText = BugUtil.getText("INTERFACE_GREAT_PERSON_CITY_TURNS", (sGP, city.getName(), iGPTurns))
			else:
				szText = BugUtil.getText("INTERFACE_GREAT_PERSON_TURNS", (sGP, iGPTurns))
		else:
			if (bIncludeCityName):
				szText = BugUtil.getText("INTERFACE_GREAT_PERSON_CITY", (sGP, city.getName()))
			else:
				szText = sGP
	else:
		lPercents = calcPercentages(city)
		if (len(lPercents) == 0):
			sGP = sNextGP + ". " + sGreatPeopleChar
			if (iGPTurns):
				if (bIncludeCityName):
					szText = BugUtil.getText("INTERFACE_GREAT_PERSON_CITY_TURNS", (sGP, city.getName(), iGPTurns))
				else:
					szText = BugUtil.getText("INTERFACE_GREAT_PERSON_TURNS", (sGP, iGPTurns))
			else:
				if (bIncludeCityName):
					szText = BugUtil.getText("INTERFACE_GREAT_PERSON_CITY", (sGP, city.getName()))
				else:
					szText = sGP
		else:
			lPercents.sort()
			lPercents.reverse()
			if (bGPBarTypesOne or len(lPercents) == 1):
				iPercent, iUnit = lPercents[0]
				pInfo = gc.getUnitInfo(iUnit)
				sGP = sNextGP + ". " + sGreatPeopleChar + " (" + unicode(pInfo.getDescription()) + ")"
				if (iGPTurns):
					if (bIncludeCityName):
						szText = BugUtil.getText("INTERFACE_GREAT_PERSON_CITY_TURNS", (sGP, city.getName(), iGPTurns))
					else:
						szText = BugUtil.getText("INTERFACE_GREAT_PERSON_TURNS", (sGP, iGPTurns))
				else:
					if (bIncludeCityName):
						szText = BugUtil.getText("INTERFACE_GREAT_PERSON_CITY", (sGP, city.getName()))
					else:
						szText = sGP
			else:
				sGP = sNextGP + ". " + sGreatPeopleChar
				if (iGPTurns):
					if (bIncludeCityName):
						szText = BugUtil.getText("INTERFACE_GREAT_PERSON_CITY_TURNS", (sGP, city.getName(), iGPTurns))
					else:
						szText = BugUtil.getText("INTERFACE_GREAT_PERSON_TURNS", (sGP, iGPTurns))
				else:
					if (bIncludeCityName):
						szText = BugUtil.getText("INTERFACE_GREAT_PERSON_CITY", (sGP, city.getName()))
					else:
						szText = sGP + u":"
				szTypes = ""
				for iPercent, iUnit in lPercents:
					szNewTypes = szTypes + u" %c%d%%" % (getUnitIcon(iUnit), iPercent)
					szNewText = szText + u"<font=2> -%s</font>" % szTypes
					if (CyInterface().determineWidth(szNewText) > iGPBarWidth - 10):
						# Keep under width
						break
					szTypes = szNewTypes
				if (len(szTypes) > 0):
					szText += u"<font=2> -%s</font>" % szTypes
	return szText
