## DiplomacyUtil
##
## Utilities for handling and dispatching Diplomacy events and acquiring
## proposed trades from the (unmoddable) CyDiplomacy screen.
##
## Contacting Rivals
##
##   canContact(playerOrID, toPlayerOrID)
##     Returns True if <player> can attempt to contact <toPlayer> given game settings, 
##     initial contact, and war-time situation.
##
##   isWillingToTalk(playerOrID, toPlayerOrID)
##     Returns True if <player> is willing to talk to <toPlayer>.
##
## TODO: switch to init()
##
## Notes
##   - Must be initialized externally by calling addEvents(eventManager)
##
## Copyright (c) 2008 The BUG Mod.
##
## Author: EmperorFool

from CvPythonExtensions import *
import AttitudeUtil
import BugUtil
import BugDll
import GameUtil
import PlayerUtil
import TradeUtil

MAX_TRADE_DATA = 50  # avoid an infinite loop

gc = CyGlobalContext()
diplo = CyDiplomacy()

# comment-type -> ( event-type , trade-type )
g_eventsByCommentType = {}
g_eventManager = None


## Contacting Rivals

def canContact(playerOrID, toPlayerOrID):
	"""
	Returns True if <player> can attempt to contact <toPlayer> given game settings, 
	initial contact, and war-time situation without regard to willingness to talk.
	
	- They must not be the same player
	- <toPlayer> must be alive, not minor, and not a barbarian
	- Their teams must have met
	- If they are at war, they must be able to sign a peace deal (no Always War or Permanent War/Peace options)
	"""
	playerID, player = PlayerUtil.getPlayerAndID(playerOrID)
	toPlayerID, toPlayer = PlayerUtil.getPlayerAndID(toPlayerOrID)
	if playerID == toPlayerID:
		return False
	if not toPlayer.isAlive() or toPlayer.isBarbarian() or toPlayer.isMinorCiv():
		return False
	if not PlayerUtil.getPlayerTeam(player).isHasMet(toPlayer.getTeam()):
		return False
	if PlayerUtil.getPlayerTeam(player).isAtWar(toPlayer.getTeam()) and (GameUtil.isAlwaysWar() or GameUtil.isPermanentWarPeace()):
		return False
	return True

def isWillingToTalk(playerOrID, toPlayerOrID):
	"""
	Returns True if <player> is willing to talk to <toPlayer>.
	
	- Every player is willing to talk to themselves
	- All human players are willing to talk
	- Uses BUG DLL if present, otherwise scans attitude hover text
	  for "Refuses to Talk!!!" in the current language
	
	Note: This function does not check if the two players can make contact.
	"""
	playerID, player = PlayerUtil.getPlayerAndID(playerOrID)
	toPlayerID = PlayerUtil.getPlayerID(toPlayerOrID)
	if playerID == toPlayerID or player.isHuman():
		# all players talk to themselves, and all humans talk
		return True
	if BugDll.isPresent():
		return player.AI_isWillingToTalk(toPlayerID)
	else:
		hover = AttitudeUtil.getAttitudeString(playerID, toPlayerID)
		if hover:
			return (hover.find(BugUtil.getPlainText("TXT_KEY_MISC_REFUSES_TO_TALK")) == -1)
		else:
			# haven't met yet
			return False


## Event Initialization

def addEvents(eventManager):
	"""Adds the diplomacy events to BugEventManager."""
	global g_eventManager
	g_eventManager = eventManager
	
	# Trade
	DiploEvent("AI_DIPLOCOMMENT_OFFER_DEAL", "DealOffered", onDealOffered, sendTrade=True)
	DiploEvent("AI_DIPLOCOMMENT_CANCEL_DEAL", "DealCanceled", onDealCanceled, sendTrade=True)
	DiploEvent("USER_DIPLOCOMMENT_ACCEPT_OFFER", "DealAccepted", onDealAccepted, sendTrade=True)
	DiploEvent("USER_DIPLOCOMMENT_REJECT_OFFER", "DealRejected", onDealRejected, sendTrade=True)
	
	# Free Stuff
	DiploEvent("AI_DIPLOCOMMENT_OFFER_CITY", "CityOffered", onCityOffered, tradeType=TradeableItems.TRADE_CITIES)
	DiploEvent("AI_DIPLOCOMMENT_GIVE_HELP", "HelpOffered", onHelpOffered, sendTrade=True)
	DiploEvent("AI_DIPLOCOMMENT_OFFER_PEACE", "PeaceOffered", onPeaceOffered)
	DiploEvent("AI_DIPLOCOMMENT_OFFER_VASSAL", "VassalOffered", onVassalOffered)
	
	# Ask for Help
	DiploEvent("AI_DIPLOCOMMENT_ASK_FOR_HELP", "HelpDemanded", onHelpDemanded, sendTrade=True)
	DiploEvent("USER_DIPLOCOMMENT_GIVE_HELP", "HelpAccepted", onHelpAccepted, sendTrade=True)
	DiploEvent("USER_DIPLOCOMMENT_REFUSE_HELP", "HelpRejected", onHelpRejected, sendTrade=True)
	
	# Demand Tribute
	DiploEvent("AI_DIPLOCOMMENT_DEMAND_TRIBUTE", "TributeDemanded", onTributeDemanded, sendTrade=True)
	DiploEvent("USER_DIPLOCOMMENT_ACCEPT_DEMAND", "TributeAccepted", onTributeAccepted, sendTrade=True)
	DiploEvent("USER_DIPLOCOMMENT_REJECT_DEMAND", "TributeRejected", onTributeRejected, sendTrade=True)
	
	# Religion
	DiploEvent("AI_DIPLOCOMMENT_RELIGION_PRESSURE", "ReligionDemanded", onReligionDemanded, 
			argFunc=lambda eFromPlayer, eToPlayer, args, data: (PlayerUtil.getStateReligion(eFromPlayer), ))
	DiploEvent("USER_DIPLOCOMMENT_CONVERT", "ReligionAccepted", onReligionAccepted,
			argFunc=lambda eFromPlayer, eToPlayer, args, data: (PlayerUtil.getStateReligion(eToPlayer), ))
	DiploEvent("USER_DIPLOCOMMENT_NO_CONVERT", "ReligionRejected", onReligionRejected,
			argFunc=lambda eFromPlayer, eToPlayer, args, data: (PlayerUtil.getStateReligion(eToPlayer), ))
	
	# Civic
	DiploEvent("AI_DIPLOCOMMENT_CIVIC_PRESSURE", "CivicDemanded", onCivicDemanded, 
			argFunc=lambda eFromPlayer, eToPlayer, args, data: (PlayerUtil.getFavoriteCivic(eFromPlayer), ))
	DiploEvent("USER_DIPLOCOMMENT_REVOLUTION", "CivicAccepted", onCivicAccepted, 
			argFunc=lambda eFromPlayer, eToPlayer, args, data: (PlayerUtil.getFavoriteCivic(eToPlayer), ))
	DiploEvent("USER_DIPLOCOMMENT_NO_REVOLUTION", "CivicRejected", onCivicRejected, 
			argFunc=lambda eFromPlayer, eToPlayer, args, data: (PlayerUtil.getFavoriteCivic(eToPlayer), ))
	
	# Join War
	DiploEvent("AI_DIPLOCOMMENT_JOIN_WAR", "WarDemanded", onWarDemanded, sendData=True)
	DiploEvent("USER_DIPLOCOMMENT_JOIN_WAR", "WarAccepted", onWarAccepted, sendData=True)
	DiploEvent("USER_DIPLOCOMMENT_NO_JOIN_WAR", "WarRejected", onWarRejected, sendData=True)
	
	# Trade Embargo
	DiploEvent("AI_DIPLOCOMMENT_STOP_TRADING", "EmbargoDemanded", onEmbargoDemanded, sendData=True)
	DiploEvent("USER_DIPLOCOMMENT_STOP_TRADING", "EmbargoAccepted", onEmbargoAccepted, sendData=True)
	DiploEvent("USER_DIPLOCOMMENT_NO_STOP_TRADING", "EmbargoRejected", onEmbargoRejected, sendData=True)


class DiploEvent:
	def __init__(self, comment, event, handler=None, 
				 sendFromPlayer=True, sendToPlayer=True, 
				 sendData=False, sendArgs=False, argFunc=None, 
				 sendTrade=False, tradeType=None):
		self.comment = comment
		self.eComment = gc.getInfoTypeForString(comment)
		if self.eComment == -1:
			raise BugUtil.ConfigError("invalid comment type %s" % comment)
		self.event = event
		self.sendFromPlayer = sendFromPlayer
		self.sendToPlayer = sendToPlayer
		self.sendData = sendData
		self.sendArgs = sendArgs
		self.argFunc = argFunc
		self.sendTrade = sendTrade
		self.tradeType = tradeType
		if tradeType:
			BugUtil.debug("DiplomacyUtil - mapped %s to %s with %s", 
					comment, event, str(tradeType))
		else:
			BugUtil.debug("DiplomacyUtil - mapped %s to %s", comment, event)
		g_eventsByCommentType[self.eComment] = self
		g_eventManager.addEventHandler(event, handler)
	
	def dispatch(self, eFromPlayer, eToPlayer, args):
		data = diplo.getData()
		BugUtil.debug("DiplomacyUtil - %s [%d] from %d to %d with %r",
				self.comment, data, eFromPlayer, eToPlayer, args)
		argList = []
		if self.sendFromPlayer:
			argList.append(eFromPlayer)
		if self.sendToPlayer:
			argList.append(eToPlayer)
		
		if self.argFunc:
			argList.extend(self.argFunc(eFromPlayer, eToPlayer, args, data))
			BugUtil.debug("DiplomacyUtil - firing %s", self.event)
		else:
			if self.sendData:
				argList.append(data)
			if self.sendArgs:
				argList.append(args)
			
			if self.sendTrade or self.tradeType:
				trade = getProposedTrade()
				if self.sendTrade:
					argList.append(trade)
				if self.tradeType:
					trades = trade.findType(self.tradeType)
					if trade and trades:
						iData = trades[0].iData
						BugUtil.debug("DiplomacyUtil - firing %s with %s %d", 
								self.event, str(self.tradeType), iData)
						argList.append(iData)
					else:
						BugUtil.debug("DiplomacyUtil - firing %s without %s", 
								self.event, str(self.tradeType))
						argList.append(-1)
			else:
				BugUtil.debug("DiplomacyUtil - firing %s", self.event)
		g_eventManager.fireEvent(self.event, *argList)


## Event Dispatching

def handleAIComment(argsList):
	eComment = argsList[0]
	commentArgsSize = argsList[1]
	if commentArgsSize:
		args = argsList[2:]
	else:
		args=[]
	dispatchEvent(eComment, diplo.getWhoTradingWith(), 
			PlayerUtil.getActivePlayerID(), args)

def handleUserResponse(argsList):
	eComment = argsList[0]
	commentArgsSize = argsList[1]
	if commentArgsSize:
		args = argsList[2:]
	else:
		args=[]
	dispatchEvent(eComment, PlayerUtil.getActivePlayerID(), 
			diplo.getWhoTradingWith(), args)

def dispatchEvent(eComment, eFromPlayer, eToPlayer, args):
	event = g_eventsByCommentType.get(eComment, None)
	if event:
		event.dispatch(eFromPlayer, eToPlayer, args)
	else:
		key = gc.getDiplomacyInfo(eComment).getType()
		BugUtil.debug("DiplomacyUtil - ignoring %s from %d to %d with %r", 
				key, eFromPlayer, eToPlayer, args)


## Event Handlers

def onDealOffered(argsList):
	#BugUtil.debug("DiplomacyUtil::onDealOffered %s" %(str(argsList)))
	eOfferPlayer, eTargetPlayer, pTrade = argsList
	BugUtil.debug("DiplomacyUtil - %s offers trade to %s: %r",
			PlayerUtil.getPlayer(eOfferPlayer).getName(), 
			PlayerUtil.getPlayer(eTargetPlayer).getName(),
			pTrade)

def onCityOffered(argsList):
	#BugUtil.debug("DiplomacyUtil::onCityOffered %s" %(str(argsList)))
	eOfferPlayer, eTargetPlayer, pTrade = argsList
	BugUtil.debug("DiplomacyUtil - %s offers city to %s: %r",
			PlayerUtil.getPlayer(eOfferPlayer).getName(), 
			PlayerUtil.getPlayer(eTargetPlayer).getName(),
			pTrade)

def onHelpOffered(argsList):
	#BugUtil.debug("DiplomacyUtil::onHelpOffered %s" %(str(argsList)))
	eOfferPlayer, eTargetPlayer, pTrade = argsList
	BugUtil.debug("DiplomacyUtil - %s offers help to %s: %r",
			PlayerUtil.getPlayer(eOfferPlayer).getName(), 
			PlayerUtil.getPlayer(eTargetPlayer).getName(),
			pTrade)

def onPeaceOffered(argsList):
	#BugUtil.debug("DiplomacyUtil::onPeaceOffered %s" %(str(argsList)))
	eOfferPlayer, eTargetPlayer = argsList
	BugUtil.debug("DiplomacyUtil - %s offers peace to %s",
			PlayerUtil.getPlayer(eOfferPlayer).getName(), 
			PlayerUtil.getPlayer(eTargetPlayer).getName())

def onVassalOffered(argsList):
	#BugUtil.debug("DiplomacyUtil::onVassalOffered %s" %(str(argsList)))
	eOfferPlayer, eTargetPlayer = argsList
	BugUtil.debug("DiplomacyUtil - %s offers vassalage to %s",
			PlayerUtil.getPlayer(eOfferPlayer).getName(), 
			PlayerUtil.getPlayer(eTargetPlayer).getName())

def onDealCanceled(argsList):
	#BugUtil.debug("DiplomacyUtil::onDealCanceled %s" %(str(argsList)))
	eOfferPlayer, eTargetPlayer, pTrade = argsList
	if eOfferPlayer != -1 and eTargetPlayer != -1 and pTrade is not None:
		BugUtil.debug("DiplomacyUtil - %s cancels deal with %s: %r",
				PlayerUtil.getPlayer(eOfferPlayer).getName(), 
				PlayerUtil.getPlayer(eTargetPlayer).getName(),
				pTrade)

def onDealAccepted(argsList):
	#BugUtil.debug("DiplomacyUtil::onDealAccepted %s" %(str(argsList)))
	eTargetPlayer, eOfferPlayer, pTrade = argsList
	BugUtil.debug("DiplomacyUtil - %s accepts trade offered by %s: %r",
			PlayerUtil.getPlayer(eTargetPlayer).getName(),
			PlayerUtil.getPlayer(eOfferPlayer).getName(), 
			pTrade)

def onDealRejected(argsList):
	#BugUtil.debug("DiplomacyUtil::onDealRejected %s" %(str(argsList)))
	eTargetPlayer, eOfferPlayer, pTrade = argsList
	BugUtil.debug("DiplomacyUtil - %s accepts trade offered by %s: %r",
			PlayerUtil.getPlayer(eTargetPlayer).getName(),
			PlayerUtil.getPlayer(eOfferPlayer).getName(), 
			pTrade)


def onHelpDemanded(argsList):
	#BugUtil.debug("DiplomacyUtil::onHelpDemanded %s" %(str(argsList)))
	eDemandPlayer, eTargetPlayer, pTrade = argsList
	szItems = ""
	for i in range(pTrade.getCount()):
		szItems = szItems + TradeUtil.format(eTargetPlayer, pTrade.getTrade(i))
	BugUtil.debug("DiplomacyUtil - %s requests help (%s) from %s",
			PlayerUtil.getPlayer(eDemandPlayer).getName(), 
			szItems,
			PlayerUtil.getPlayer(eTargetPlayer).getName())

def onHelpAccepted(argsList):
	#BugUtil.debug("DiplomacyUtil::onHelpAccepted %s" %(str(argsList)))
	eTargetPlayer, eDemandPlayer, pTrade = argsList
	szItems = ""
	for i in range(pTrade.getCount()):
		szItems = szItems + TradeUtil.format(eTargetPlayer, pTrade.getTrade(i))
	BugUtil.debug("DiplomacyUtil - %s agrees to give help (%s) to %s",
			PlayerUtil.getPlayer(eTargetPlayer).getName(), 
			szItems,
			PlayerUtil.getPlayer(eDemandPlayer).getName())

def onHelpRejected(argsList):
	#BugUtil.debug("DiplomacyUtil::onHelpRejected %s" %(str(argsList)))
	eTargetPlayer, eDemandPlayer, pTrade = argsList
	szItems = ""
	for i in range(pTrade.getCount()):
		szItems = szItems + TradeUtil.format(eTargetPlayer, pTrade.getTrade(i))
	BugUtil.debug("DiplomacyUtil - %s refuses to give help (%s) to %s",
			PlayerUtil.getPlayer(eTargetPlayer).getName(), 
			szItems,
			PlayerUtil.getPlayer(eDemandPlayer).getName())


def onTributeDemanded(argsList):
	#BugUtil.debug("DiplomacyUtil::onTributeDemanded %s" %(str(argsList)))
	eDemandPlayer, eTargetPlayer, pTrade = argsList
	szItems = ""
	for i in range(pTrade.getCount()):
		szItems = szItems + TradeUtil.format(eTargetPlayer, pTrade.getTrade(i))
	BugUtil.debug("DiplomacyUtil - %s demands a tribute (%s) from %s",
			PlayerUtil.getPlayer(eDemandPlayer).getName(), 
			szItems,
			PlayerUtil.getPlayer(eTargetPlayer).getName())

def onTributeAccepted(argsList):
	#BugUtil.debug("DiplomacyUtil::onTributeAccepted %s" %(str(argsList)))
	eTargetPlayer, eDemandPlayer, pTrade = argsList
	szItems = ""
	for i in range(pTrade.getCount()):
		szItems = szItems + TradeUtil.format(eTargetPlayer, pTrade.getTrade(i))
	BugUtil.debug("DiplomacyUtil - %s agrees to give tribute (%s) to %s",
			PlayerUtil.getPlayer(eTargetPlayer).getName(), 
			szItems,
			PlayerUtil.getPlayer(eDemandPlayer).getName())

def onTributeRejected(argsList):
	#BugUtil.debug("DiplomacyUtil::onTributeRejected %s" %(str(argsList)))
	eTargetPlayer, eDemandPlayer, pTrade = argsList
	szItems = ""
	for i in range(pTrade.getCount()):
		szItems = szItems + TradeUtil.format(eTargetPlayer, pTrade.getTrade(i))
	BugUtil.debug("DiplomacyUtil - %s refuses to give tribute (%s) to %s",
			PlayerUtil.getPlayer(eTargetPlayer).getName(), 
			szItems,
			PlayerUtil.getPlayer(eDemandPlayer).getName())

def onReligionDemanded(argsList):
	#BugUtil.debug("DiplomacyUtil::onReligionDemanded %s" %(str(argsList)))
	eDemandPlayer, eTargetPlayer, eReligion = argsList
	BugUtil.debug("DiplomacyUtil - %s asks %s to convert to %s",
			PlayerUtil.getPlayer(eDemandPlayer).getName(), 
			PlayerUtil.getPlayer(eTargetPlayer).getName(), 
			gc.getReligionInfo(eReligion).getDescription())

def onReligionAccepted(argsList):
	#BugUtil.debug("DiplomacyUtil::onReligionAccepted %s" %(str(argsList)))
	eTargetPlayer, eDemandPlayer, eReligion = argsList
	BugUtil.debug("DiplomacyUtil - %s accepts demand from %s to convert to %s",
			PlayerUtil.getPlayer(eTargetPlayer).getName(), 
			PlayerUtil.getPlayer(eDemandPlayer).getName(), 
			gc.getReligionInfo(eReligion).getDescription())

def onReligionRejected(argsList):
	#BugUtil.debug("DiplomacyUtil::onReligionRejected %s" %(str(argsList)))
	eTargetPlayer, eDemandPlayer, eReligion = argsList
	BugUtil.debug("DiplomacyUtil - %s rejects demand from %s to convert to %s",
			PlayerUtil.getPlayer(eTargetPlayer).getName(), 
			PlayerUtil.getPlayer(eDemandPlayer).getName(), 
			gc.getReligionInfo(eReligion).getDescription())


def onCivicDemanded(argsList):
	#BugUtil.debug("DiplomacyUtil::onCivicDemanded %s" %(str(argsList)))
	eDemandPlayer, eTargetPlayer, eCivic = argsList
	BugUtil.debug("DiplomacyUtil - %s asks %s to switch to %s",
			PlayerUtil.getPlayer(eDemandPlayer).getName(), 
			PlayerUtil.getPlayer(eTargetPlayer).getName(), 
			gc.getCivicInfo(eCivic).getDescription())

def onCivicAccepted(argsList):
	#BugUtil.debug("DiplomacyUtil::onCivicAccepted %s" %(str(argsList)))
	eTargetPlayer, eDemandPlayer, eCivic = argsList
	BugUtil.debug("DiplomacyUtil - %s accepts demand from %s to switch to %s",
			PlayerUtil.getPlayer(eTargetPlayer).getName(), 
			PlayerUtil.getPlayer(eDemandPlayer).getName(), 
			gc.getCivicInfo(eCivic).getDescription())

def onCivicRejected(argsList):
	#BugUtil.debug("DiplomacyUtil::onCivicRejected %s" %(str(argsList)))
	eTargetPlayer, eDemandPlayer, eCivic = argsList
	BugUtil.debug("DiplomacyUtil - %s rejects demand from %s to switch to %s",
			PlayerUtil.getPlayer(eTargetPlayer).getName(), 
			PlayerUtil.getPlayer(eDemandPlayer).getName(), 
			gc.getCivicInfo(eCivic).getDescription())


def onWarDemanded(argsList):
	#BugUtil.debug("DiplomacyUtil::onWarDemanded %s" %(str(argsList)))
	eDemandPlayer, eTargetPlayer, eVictim = argsList
	BugUtil.debug("DiplomacyUtil - %s asks %s to declare war on %s",
			PlayerUtil.getPlayer(eDemandPlayer).getName(), 
			PlayerUtil.getPlayer(eTargetPlayer).getName(), 
			PlayerUtil.getPlayer(eVictim).getName())

def onWarAccepted(argsList):
	#BugUtil.debug("DiplomacyUtil::onWarAccepted %s" %(str(argsList)))
	eTargetPlayer, eDemandPlayer, eVictim = argsList
	BugUtil.debug("DiplomacyUtil - %s agrees to demand from %s to declare war on %s",
			PlayerUtil.getPlayer(eTargetPlayer).getName(), 
			PlayerUtil.getPlayer(eDemandPlayer).getName(), 
			PlayerUtil.getPlayer(eVictim).getName())

def onWarRejected(argsList):
	#BugUtil.debug("DiplomacyUtil::onWarRejected %s" %(str(argsList)))
	eTargetPlayer, eDemandPlayer, eVictim = argsList
	BugUtil.debug("DiplomacyUtil - %s rejects demand from %s to declare war on %s",
			PlayerUtil.getPlayer(eTargetPlayer).getName(), 
			PlayerUtil.getPlayer(eDemandPlayer).getName(), 
			PlayerUtil.getPlayer(eVictim).getName())


def onEmbargoDemanded(argsList):
	#BugUtil.debug("DiplomacyUtil::onEmbargoDemanded %s" %(str(argsList)))
	eDemandPlayer, eTargetPlayer, eVictim = argsList
	BugUtil.debug("DiplomacyUtil - %s asks %s to stop trading with %s",
			PlayerUtil.getPlayer(eDemandPlayer).getName(), 
			PlayerUtil.getPlayer(eTargetPlayer).getName(), 
			PlayerUtil.getPlayer(eVictim).getName())

def onEmbargoAccepted(argsList):
	#BugUtil.debug("DiplomacyUtil::onEmbargoAccepted %s" %(str(argsList)))
	eTargetPlayer, eDemandPlayer, eVictim = argsList
	BugUtil.debug("DiplomacyUtil - %s agrees to demand from %s to stop trading with %s",
			PlayerUtil.getPlayer(eTargetPlayer).getName(), 
			PlayerUtil.getPlayer(eDemandPlayer).getName(), 
			PlayerUtil.getPlayer(eVictim).getName())

def onEmbargoRejected(argsList):
	#BugUtil.debug("DiplomacyUtil::onEmbargoRejected %s" %(str(argsList)))
	eTargetPlayer, eDemandPlayer, eVictim = argsList
	BugUtil.debug("DiplomacyUtil - %s rejects demand from %s to stop trading with %s",
			PlayerUtil.getPlayer(eTargetPlayer).getName(), 
			PlayerUtil.getPlayer(eDemandPlayer).getName(), 
			PlayerUtil.getPlayer(eVictim).getName())


## Proposed Trade Functions

def getProposedTrade():
	trade = TradeUtil.Trade(PlayerUtil.getActivePlayerID(), diplo.getWhoTradingWith())
	if not diplo.ourOfferEmpty():
		getProposedTradeData(diplo.getPlayerTradeOffer, trade.addTrade)
	if not diplo.theirOfferEmpty():
		getProposedTradeData(diplo.getTheirTradeOffer, trade.addOtherTrade)
	BugUtil.debug("DiplomacyUtil.getProposedTrade - %r", trade)
	return trade

def getProposedTradeData(getFunc, addFunc):
	for index in range(MAX_TRADE_DATA):
		data = getFunc(index)
		if data:
			addFunc(data)
		else:
			break
	else:
		BugUtil.warn("DiplomacyUtil.getProposedTradeData - reached %d items, ignoring rest",
				MAX_TRADE_DATA)
