from CvPythonExtensions import *
import CvUtil
import ScreenInput
import CvScreenEnums
import CvEventInterface

from AStarTools import *
import MonkeyTools as mt
import UnitUtil
import string

import BugCore
PleOpt = BugCore.game.PLE

# globals
gc = CyGlobalContext()
ArtFileMgr = CyArtFileMgr()
localText = CyTranslator()

# MULTI LIST
#####################
iMultiListXL = 318
iMultiListXR = 332

class PLE:
	def __init__(self):
#	def PLE_initialize(self):

		# filter constants
		self.nPLEFilterModeCanMove		= 0x0001
		self.nPLEFilterModeCantMove		= 0x0002
		self.nPLEFilterModeWound		= 0x0004
		self.nPLEFilterModeNotWound		= 0x0008
		self.nPLEFilterModeAir 			= 0x0010
		self.nPLEFilterModeSea 			= 0x0020
		self.nPLEFilterModeLand			= 0x0040
		self.nPLEFilterModeDom			= 0x0080
		self.nPLEFilterModeMil			= 0x0100
		self.nPLEFilterModeOwn			= 0x0200
		self.nPLEFilterModeForeign		= 0x0400

		self.nPLEFilterGroupHealth		= self.nPLEFilterModeWound | self.nPLEFilterModeNotWound
		self.nPLEFilterGroupDomain		= self.nPLEFilterModeAir | self.nPLEFilterModeSea | self.nPLEFilterModeLand
		self.nPLEFilterGroupType		= self.nPLEFilterModeDom | self.nPLEFilterModeMil
		self.nPLEFilterGroupOwner		= self.nPLEFilterModeOwn | self.nPLEFilterModeForeign
		self.nPLEFilterGroupMove		= self.nPLEFilterModeCanMove | self.nPLEFilterModeCantMove

		self.nPLEAllFilters				= self.nPLEFilterGroupHealth | self.nPLEFilterGroupDomain | self.nPLEFilterGroupType | self.nPLEFilterGroupOwner | self.nPLEFilterGroupMove

		# set all filters to active -> all units 
		self.nPLEFilter 				= self.nPLEAllFilters

		self.PLOT_LIST_BUTTON_NAME		= "MyPlotListButton"
		self.PLOT_LIST_MINUS_NAME		= "MyPlotListMinus"
		self.PLOT_LIST_PLUS_NAME		= "MyPlotListPlus"
		self.PLOT_LIST_UP_NAME			= "MyPlotListUp"
		self.PLOT_LIST_DOWN_NAME		= "MyPlotListDown"
		self.PLOT_LIST_PROMO_NAME		= "MyPlotListPromo"
		self.PLOT_LIST_UPGRADE_NAME		= "MyPlotListUpgrade"

		self.PLE_VIEW_MODE			= "PLE_VIEW_MODE1"
		self.PLE_MODE_STANDARD		= "PLE_MODE_STANDARD1"
		self.PLE_MODE_MULTILINE		= "PLE_MODE_MULTILINE1"
		self.PLE_MODE_STACK_VERT	= "PLE_MODE_STACK_VERT1"
		self.PLE_MODE_STACK_HORIZ	= "PLE_MODE_STACK_HORIZ1"
		self.PLE_VIEW_MODES = (self.PLE_MODE_STANDARD, 
							   self.PLE_MODE_MULTILINE,
							   self.PLE_MODE_STACK_VERT,
							   self.PLE_MODE_STACK_HORIZ )
		self.PLE_VIEW_MODE_CYCLE = {self.PLE_MODE_STANDARD : self.PLE_MODE_MULTILINE,
									self.PLE_MODE_MULTILINE : self.PLE_MODE_STACK_VERT,
									self.PLE_MODE_STACK_VERT : self.PLE_MODE_STACK_HORIZ,
									self.PLE_MODE_STACK_HORIZ : self.PLE_MODE_STANDARD }
		self.PLE_VIEW_MODE_ART = {self.PLE_MODE_STANDARD : "PLE_MODE_STANDARD",
								  self.PLE_MODE_MULTILINE : "PLE_MODE_MULTILINE",
								  self.PLE_MODE_STACK_VERT : "PLE_MODE_STACK_VERT",
								  self.PLE_MODE_STACK_HORIZ : "PLE_MODE_STACK_HORIZ" }

		self.PLE_RESET_FILTERS		= "PLE_RESET_FILTERS1"
		self.PLE_FILTER_NOTWOUND	= "PLE_FILTER_NOTWOUND1"
		self.PLE_FILTER_WOUND		= "PLE_FILTER_WOUND1"
		self.PLE_FILTER_LAND		= "PLE_FILTER_LAND1"
		self.PLE_FILTER_SEA			= "PLE_FILTER_SEA1"
		self.PLE_FILTER_AIR			= "PLE_FILTER_AIR1"
		self.PLE_FILTER_MIL			= "PLE_FILTER_MIL1"
		self.PLE_FILTER_DOM			= "PLE_FILTER_DOM1"
		self.PLE_FILTER_OWN			= "PLE_FILTER_OWN1"
		self.PLE_FILTER_FOREIGN		= "PLE_FILTER_FOREIGN1"
		self.PLE_FILTER_CANMOVE		= "PLE_FILTER_CANMOVE1"
		self.PLE_FILTER_CANTMOVE	= "PLE_FILTER_CANTMOVE1"

		self.PLE_PROMO_BUTTONS_UNITINFO = "PLE_PROMO_BUTTONS_UNITINFO"

		self.PLE_GRP_UNITTYPE		= "PLE_GRP_UNITTYPE1"
		self.PLE_GRP_GROUPS			= "PLE_GRP_GROUPS1"
		self.PLE_GRP_PROMO			= "PLE_GRP_PROMO1"
		self.PLE_GRP_UPGRADE		= "PLE_GRP_UPGRADE1"
		self.PLE_GROUP_MODES = ( self.PLE_GRP_UNITTYPE, 
								 self.PLE_GRP_GROUPS,
								 self.PLE_GRP_PROMO,
								 self.PLE_GRP_UPGRADE )

		self.UNIT_INFO_PANE			= "PLE_UNIT_INFO_PANE_ID"
		self.UNIT_INFO_TEXT			= "PLE_UNIT_INFO_TEXT_ID"
		self.UNIT_INFO_TEXT_SHADOW	= "PLE_UNIT_INFO_TEXT_SHADOW_ID"

		self.iColOffset 			= 0
		self.iRowOffset 			= 0
		self.iVisibleUnits 			= 0
		self.pActPlot 				= 0
		self.pOldPlot 				= self.pActPlot
	#		self.sPLEMode 				= self.PLE_MODE_MULTILINE
		self.iMaxPlotListIcons 		= 0

	#		self.nPLEGrpMode 			= self.PLE_GRP_UNITTYPE
	#		self.nPLELastGrpMode  	    = self.nPLEGrpMode
		self.pActPlotListUnit		= 0
		self.iActPlotListGroup		= 0
	#		self.pLastPlotListUnit		= 0
	#		self.iLastPlotListGroup		= 0

		self.IDX_PLAYER				= 0
		self.IDX_DOMAIN 			= 1
		self.IDX_GROUPID			= 2
		self.IDX_COMBAT				= 3
		self.IDX_UNITTYPE			= 4
		self.IDX_LEVEL				= 5
		self.IDX_XP					= 6
		self.IDX_TRANSPORTID		= 7
		self.IDX_CARGOID			= 8
		self.IDX_UNITID				= 9
		self.IDX_UNIT				= 10

		self.lPLEUnitList 			= []
		self.lPLEUnitListTempOK		= []
		self.lPLEUnitListTempNOK	= []
		self.dPLEUnitInfo 			= {}

		self.iLoopCnt 				= 0
	#		self.bPLEHide 				= False

		self.dUnitPromoList			= {}
		self.dUnitUpgradeList		= {}

	#		self.bInit					= False

		self.ASMA 					= AStarMoveArea()

		self.tLastMousePos			= (0,0)
		self.bInfoPaneActive		= False
		self.bUnitPromoButtonsActive = False
		self.iMousePosTol			= 30
		self.iInfoPaneCnt			= 0
		self.iLastInfoPaneCnt		= -1

		self.xResolution = 0
		self.yResolution = 0

		self.bShowWoundedIndicator = False
		self.bShowGreatGeneralIndicator = False
		self.bShowPromotionIndicator = False
		self.bShowUpgradeIndicator = False
		self.bShowMissionInfo = False

		self.bShowHealthBar = False
		self.bHideHealthBarWhileFighting = False
		self.bShowMoveBar = False

		self.bPLEHide = True

	def PLE_CalcConstants(self):
			self.iMaxPlotListIcons = self.getMaxCol() * self.getMaxRow()
			self.sPLEMode = self.PLE_MODE_MULTILINE
			self.nPLEGrpMode = self.PLE_GRP_UNITTYPE
			self.nPLELastGrpMode = self.nPLEGrpMode
			self.sPLEMode = self.PLE_VIEW_MODES[PleOpt.getDefaultViewMode()]
			self.nPLEGrpMode = self.PLE_GROUP_MODES[PleOpt.getDefaultGroupMode()]
			self.setPLEUnitList(True)

			self.pOldPlot = 0

			self.CFG_INFOPANE_PIX_PER_LINE_1 			= 24
			self.CFG_INFOPANE_PIX_PER_LINE_2 			= 19
			self.CFG_INFOPANE_DX 					    = 290

			self.CFG_INFOPANE_Y		 			= self.yResolution - PleOpt.getInfoPaneY()
			self.CFG_INFOPANE_BUTTON_SIZE		= self.CFG_INFOPANE_PIX_PER_LINE_1 - 2
			self.CFG_INFOPANE_BUTTON_PER_LINE	= self.CFG_INFOPANE_DX / self.CFG_INFOPANE_BUTTON_SIZE
			self.CFG_INFOPANE_Y2				= self.CFG_INFOPANE_Y + 105


	def updatePlotListButtons_PLE( self, screen, xResolution, yResolution ):

		self.xResolution = xResolution
		self.yResolution = yResolution

		self.iLoopCnt += 1

		self.pActPlot = CyInterface().getSelectionPlot()
		# if the plot changed, reset plot list offset
		if (self.pOldPlot):
			# check if plot has changed
			if (self.pOldPlot.getX() != self.pActPlot.getX()) or (self.pOldPlot.getY() != self.pActPlot.getY()):
				self.pOldPlot = self.pActPlot
				self.iColOffset = 0
				self.iRowOffset = 0
				self.setPLEUnitList(True)
				# mt.debug("update plot:"+str(self.iLoopCnt))
		else:
			# initialization
			self.pOldPlot = self.pActPlot
			self.setPLEUnitList(True)
			# mt.debug("update init:"+str(self.iLoopCnt))

		# check if the current unit has changed (eg. when it is unloaded). 
		# if so, do a reinit PLE Unit List
		pHeadSelectedUnit = CyInterface().getHeadSelectedUnit()
		try:
			id = pHeadSelectedUnit.getID()
			# mt.debug("Sel Unit:"+str(id))
			if (id in self.dPLEUnitInfo):
				lActUnitInfo = self.getPLEUnitInfo( pHeadSelectedUnit )
				if (lActUnitInfo <> self.dPLEUnitInfo[ id ]):
					self.setPLEUnitList(True)
					# mt.debug("update unload:"+str(self.iLoopCnt))
		except:
			# mt.debug("Sel Unit: <fail>")
			pass

		if (self.getPLEUnitList()):
			self.getUnitList(self.pActPlot)
			self.setPLEUnitList(False)
			# mt.debug("Sel Unit: UPDATE!")

		self.listPLEButtons = [(0,0,0)] * self.iMaxPlotListIcons

		for i in range(gc.getNumPromotionInfos()):
			szName = "PromotionButton" + str(i)
			screen.moveToFront( szName )

		# hide all buttons
		self.hidePlotListButtonPLEObjects(screen)

		if ( self.pActPlot and CyInterface().getShowInterface() != InterfaceVisibility.INTERFACE_HIDE_ALL and CyEngine().isGlobeviewUp() == False):

			nRow = 0
			nCol = 0
			self.iVisibleUnits = CyInterface().getNumVisibleUnits()
			
			if self.sPLEMode == self.PLE_MODE_STANDARD:
				iCount = -self.iColOffset
				nNumUnits = self.getMaxCol()
			elif self.sPLEMode == self.PLE_MODE_MULTILINE:
				iCount = 0
				nNumUnits = self.iVisibleUnits
			elif self.sPLEMode == self.PLE_MODE_STACK_VERT:
				iCount = 0
				nCol = -self.iColOffset
				nNumUnits = self.iVisibleUnits
			elif self.sPLEMode == self.PLE_MODE_STACK_HORIZ:
				iCount = 0
				nRow = -self.iRowOffset
				nNumUnits = self.iVisibleUnits
				
			bUpArrow = False
			bDownArrow = False
			bFirstLoop = True
			
	# BUG - PLE - end

			bLeftArrow = False
			bRightArrow = False

			iLastUnitType = UnitTypes.NO_UNIT
			iLastGroupID  = 0
			# loop for all units on the plot
			for i in range(len(self.lPLEUnitList)):
				pLoopUnit = self.getInterfacePlotUnit(i)

				if (pLoopUnit):
					# checks if the units matches actual filters
					if (self.checkDisplayFilter(pLoopUnit)):

						if not pLoopUnit.isCargo():
							iActUnitType = pLoopUnit.getUnitType()
							iActGroupID  = pLoopUnit.getGroupID()

						# standard view with scroll arrows
						if (self.sPLEMode == self.PLE_MODE_STANDARD):
							if (self.iColOffset > 0):
								bLeftArrow = True
							if ((self.iVisibleUnits - self.getMaxCol() - self.iColOffset) > 0):
								bRightArrow = True
								
							if ((iCount >= 0) and (iCount < nNumUnits )):
								nCol = iCount
								nRow = 0
								self.displayUnitPlotListObjects(screen, pLoopUnit, nRow, nCol)

						# multiline view
						elif (self.sPLEMode == self.PLE_MODE_MULTILINE):

							if (self.iRowOffset > 0):
								bDownArrow = True
							if ((nRow >= self.getMaxRow()) > 0):
								bUpArrow = True
								
							nCol = self.getCol( iCount ) 
							nRow = self.getRow( iCount ) - self.iRowOffset
							if ((nRow >= 0) and (iCount < nNumUnits ) and (nRow < self.getMaxRow())):
								self.displayUnitPlotListObjects(screen, pLoopUnit, nRow, nCol)
								
						# vertical stack view
						elif (self.sPLEMode == self.PLE_MODE_STACK_VERT):

							if (self.iColOffset > 0):
								bLeftArrow = True
							if (nCol >= self.getMaxCol()):
								bRightArrow = True
								
							if (self.nPLEGrpMode == self.PLE_GRP_UNITTYPE):
								if (iLastUnitType != UnitTypes.NO_UNIT):
									if (iActUnitType != iLastUnitType):
										nCol += 1
										nRow = 0
									else:
										nRow += 1
										if (nRow >= self.getMaxRow()):
											nRow = 0
											nCol += 1
							elif (self.nPLEGrpMode == self.PLE_GRP_GROUPS):
								if (iLastGroupID != 0):
									if (iActGroupID != iLastGroupID):
										nCol += 1
										nRow = 0
									else:
										nRow += 1
										if (nRow >= self.getMaxRow()):
											nRow = 0
											nCol += 1
							elif (self.nPLEGrpMode == self.PLE_GRP_PROMO):
								nRow = 0
								if not bFirstLoop:
									nCol += 1
							elif (self.nPLEGrpMode == self.PLE_GRP_UPGRADE):
								nRow = 0
								if not bFirstLoop:
									nCol += 1

							if ((nCol >= 0) and (iCount < nNumUnits ) and (nCol < self.getMaxCol())):
								self.displayUnitPlotListObjects(screen, pLoopUnit, nRow, nCol)
								if (self.nPLEGrpMode == self.PLE_GRP_PROMO):
									self.displayUnitPromos(screen, pLoopUnit, nRow, nCol)
								elif (self.nPLEGrpMode == self.PLE_GRP_UPGRADE):
									self.displayUnitUpgrades(screen, pLoopUnit, nRow, nCol)

						# horizontal stack view
						elif (self.sPLEMode == self.PLE_MODE_STACK_HORIZ):

							if (self.iRowOffset > 0):
								bDownArrow = True
							if ((nRow >= self.getMaxRow()) > 0):
								bUpArrow = True
								
							if (self.nPLEGrpMode == self.PLE_GRP_UNITTYPE):
								if ((iLastUnitType != UnitTypes.NO_UNIT)):
									if (iActUnitType != iLastUnitType):
										nRow += 1
										nCol = 0
									else:
										nCol += 1
										if (nCol >= self.getMaxCol()):
											nCol = 0
											nRow += 1
							elif (self.nPLEGrpMode == self.PLE_GRP_GROUPS):
								if (iLastGroupID != 0):
									if (iActGroupID != iLastGroupID):
										nRow += 1
										nCol = 0
									else:
										nCol += 1
										if (nCol >= self.getMaxCol()):
											nCol = 0
											nRow += 1
							elif (self.nPLEGrpMode == self.PLE_GRP_PROMO):
								nCol= 0
								if not bFirstLoop:
									nRow += 1
							elif (self.nPLEGrpMode == self.PLE_GRP_UPGRADE):
								nCol= 0
								if not bFirstLoop:
									nRow += 1

							if ((nRow >= 0) and (iCount < nNumUnits ) and (nRow < self.getMaxRow())):
								self.displayUnitPlotListObjects(screen, pLoopUnit, nRow, nCol)
								if (self.nPLEGrpMode == self.PLE_GRP_PROMO):
									self.displayUnitPromos(screen, pLoopUnit, nRow, nCol)
								elif (self.nPLEGrpMode == self.PLE_GRP_UPGRADE):
									self.displayUnitUpgrades(screen, pLoopUnit, nRow, nCol)

						iCount += 1
						
						iLastUnitType 	= iActUnitType
						iLastGroupID  	= iActGroupID
						bFirstLoop 		= false

			# left/right scroll buttons
			if 	( ( self.sPLEMode == self.PLE_MODE_STANDARD ) and ( self.iVisibleUnits > self.getMaxCol() ) ) or \
				( ( self.sPLEMode == self.PLE_MODE_STACK_VERT ) and ( ( nCol >= self.getMaxCol() or ( self.iColOffset > 0 ) ) ) ):
				screen.enable( self.PLOT_LIST_MINUS_NAME, bLeftArrow )
				screen.show( self.PLOT_LIST_MINUS_NAME )
				screen.enable( self.PLOT_LIST_PLUS_NAME, bRightArrow )
				screen.show( self.PLOT_LIST_PLUS_NAME )
				
			# up/Down scroll buttons
			if 	( ( self.sPLEMode == self.PLE_MODE_MULTILINE ) and ( ( nRow >= self.getMaxRow() or ( self.iRowOffset > 0 ) ) ) ) or \
				( ( self.sPLEMode == self.PLE_MODE_STACK_HORIZ ) and ( ( nRow >= self.getMaxRow() or ( self.iRowOffset > 0 ) ) ) ):
				screen.enable(self.PLOT_LIST_UP_NAME, bUpArrow )
				screen.show( self.PLOT_LIST_UP_NAME )
				screen.enable( self.PLOT_LIST_DOWN_NAME, bDownArrow )
				screen.show( self.PLOT_LIST_DOWN_NAME )
				
			self.showPlotListButtonObjects(screen)
			
		else:
			self.hidePlotListButtonPLEObjects(screen)
	# BUG - PLE - end

		return 0





	# PLE Mode Switcher functions
	def onClickPLEResetFilters(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			self.resetPLEFilters()
			return 1
		elif ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CURSOR_MOVE_ON ):
			sFullKey = "TXT_KEY_PLE_RESET_FILTERS"
			bSelected = self.isPLEFilter(self.nPLEAllFilters)
			if ( bSelected ):
				sFullKey += "_ON"
			self.displayHelpHover(sFullKey)
			return 1
		elif ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CURSOR_MOVE_OFF ):
			self.hideInfoPane()
			return 1
		return 0


	# PLE Movement Filters
	def onClickPLEFilterCanMove(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			self.setPLEFilter(self.nPLEFilterModeCanMove, self.nPLEFilterGroupMove)
			return 1
		else:
			return self.handleHoverPLEFilter(inputClass, "CANMOVE", self.nPLEFilterModeCanMove)

	def onClickPLEFilterCantMove(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			self.setPLEFilter(self.nPLEFilterModeCantMove, self.nPLEFilterGroupMove)
			return 1
		else:
			return self.handleHoverPLEFilter(inputClass, "CANTMOVE", self.nPLEFilterModeCantMove)


	# PLE Health Filters
	def onClickPLEFilterNotWound(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			self.setPLEFilter(self.nPLEFilterModeNotWound, self.nPLEFilterGroupHealth)
			return 1
		else:
			return self.handleHoverPLEFilter(inputClass, "HEALTHY", self.nPLEFilterModeNotWound)
			
	def onClickPLEFilterWound(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			self.setPLEFilter(self.nPLEFilterModeWound, self.nPLEFilterGroupHealth)
			return 1
		else:
			return self.handleHoverPLEFilter(inputClass, "WOUNDED", self.nPLEFilterModeWound)


	# PLE Domain Filters
	def onClickPLEFilterLand(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			self.setPLEFilter(self.nPLEFilterModeLand, self.nPLEFilterGroupDomain)
			return 1
		else:
			return self.handleHoverPLEFilter(inputClass, "LAND", self.nPLEFilterModeLand)

	def onClickPLEFilterSea(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			self.setPLEFilter(self.nPLEFilterModeSea, self.nPLEFilterGroupDomain)
			return 1
		else:
			return self.handleHoverPLEFilter(inputClass, "SEA", self.nPLEFilterModeSea)

	def onClickPLEFilterAir(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			self.setPLEFilter(self.nPLEFilterModeAir, self.nPLEFilterGroupDomain)
			return 1
		else:
			return self.handleHoverPLEFilter(inputClass, "AIR", self.nPLEFilterModeAir)


	# PLE Domain Filters
	def onClickPLEFilterMil(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			self.setPLEFilter(self.nPLEFilterModeMil, self.nPLEFilterGroupType)
			return 1
		else:
			return self.handleHoverPLEFilter(inputClass, "MIL", self.nPLEFilterModeMil)

	def onClickPLEFilterDom(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			self.setPLEFilter(self.nPLEFilterModeDom, self.nPLEFilterGroupType)
			return 1
		else:
			return self.handleHoverPLEFilter(inputClass, "DOM", self.nPLEFilterModeDom)
			

	# PLE Ownership Filters
	def onClickPLEFilterOwn(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			self.setPLEFilter(self.nPLEFilterModeOwn, self.nPLEFilterGroupOwner)
			return 1
		else:
			return self.handleHoverPLEFilter(inputClass, "OWN", self.nPLEFilterModeOwn)
			
	def onClickPLEFilterForeign(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			self.setPLEFilter(self.nPLEFilterModeForeign, self.nPLEFilterGroupOwner)
			return 1
		else:
			return self.handleHoverPLEFilter(inputClass, "FOREIGN", self.nPLEFilterModeForeign)


	# PLE Grouping Modes
	def onClickPLEGrpUnittype(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			if (self.nPLEGrpMode == self.PLE_GRP_UNITTYPE):
				self.setPLEGroupMode(self.PLE_GRP_GROUPS)
				self.nPLELastGrpMode = self.PLE_GRP_GROUPS
			elif (self.nPLEGrpMode == self.PLE_GRP_GROUPS):
				self.setPLEGroupMode(self.PLE_GRP_UNITTYPE)
				self.nPLELastGrpMode = self.PLE_GRP_UNITTYPE
			else:
				self.setPLEGroupMode(self.nPLELastGrpMode)
			return 1
		else:
			return self.handleHoverPLEGrpMode(inputClass, "STANDARD", self.PLE_GRP_UNITTYPE)

	def onClickPLEGrpGroups(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			self.setPLEGroupMode(self.PLE_GRP_GROUPS)
			return 1
		else:
			return self.handleHoverPLEGrpMode(inputClass, "GROUPS", self.PLE_GRP_GROUPS)

	def onClickPLEGrpPromo(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			if ( self.nPLEGrpMode == self.PLE_GRP_PROMO ):
				self.setPLEGroupMode(self.nPLELastGrpMode)
			else:
				self.setPLEGroupMode(self.PLE_GRP_PROMO)
			return 1
		else:
			return self.handleHoverPLEGrpMode(inputClass, "PROMO", self.PLE_GRP_PROMO)

	def onClickPLEGrpUpgrade(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			if ( self.nPLEGrpMode == self.PLE_GRP_UPGRADE ):
				self.setPLEGroupMode(self.nPLELastGrpMode)
			else:
				self.setPLEGroupMode(self.PLE_GRP_UPGRADE)
			return 1
		else:
			return self.handleHoverPLEGrpMode(inputClass, "UPGRADE", self.PLE_GRP_UPGRADE)


	# PLE View Modes
	def onClickPLEViewMode(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			if ( self.sPLEMode in self.PLE_VIEW_MODE_CYCLE ):
				self.setPLEViewMode(self.PLE_VIEW_MODE_CYCLE[self.sPLEMode])
			else:
				self.setPLEViewMode(PleOpt.getDefaultViewMode())
			return 1
		elif ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CURSOR_MOVE_ON ):
			sFullKey = "TXT_KEY_PLE_VIEW_MODE"
			self.displayHelpHover(sFullKey)
			return 1
		elif ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CURSOR_MOVE_OFF ):
			self.hideInfoPane()
			return 1
		return 0
				
	def onClickPLEModeStandard(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			self.setPLEViewMode(self.PLE_MODE_STANDARD)
			return 1
		else:
			return self.handleHoverPLEViewMode(inputClass, "STANDARD", self.PLE_MODE_STANDARD)
				
	def onClickPLEModeMultiline(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			self.setPLEViewMode(self.PLE_MODE_MULTILINE)
			return 1
		else:
			return self.handleHoverPLEViewMode(inputClass, "MULTILINE", self.PLE_MODE_MULTILINE)

	def onClickPLEModeStackVert(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			self.setPLEViewMode(self.PLE_MODE_STACK_VERT)
			return 1
		else:
			return self.handleHoverPLEViewMode(inputClass, "STACK_VERT", self.PLE_MODE_STACK_VERT)

	def onClickPLEModeStackHoriz(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			self.setPLEViewMode(self.PLE_MODE_STACK_HORIZ)
			return 1
		else:
			return self.handleHoverPLEViewMode(inputClass, "STACK_HORIZ", self.PLE_MODE_STACK_HORIZ)





	def resetPLEFilters(self):
		self.nPLEFilter = self.nPLEAllFilters
		CyInterface().setDirty(InterfaceDirtyBits.PlotListButtons_DIRTY_BIT, True)

	def displayHelpHover(self, sKey):
		sText = u"<font=2>%s</font>" % BugUtil.getPlainText(sKey)
		self.displayInfoPane(sText)

	# hides the info pane
	def hideInfoPane(self):
		screen = CyGInterfaceScreen( "MainInterface", CvScreenEnums.MAIN_INTERFACE )
		screen.hide(self.UNIT_INFO_TEXT)
		screen.hide(self.UNIT_INFO_TEXT_SHADOW)
		screen.hide(self.UNIT_INFO_PANE)
		self.bInfoPaneActive = False
		self.iLastInfoPaneCnt = self.iInfoPaneCnt

	# Returns True if the given filter is active
	# You can pass in a filter group to see if any of its filters is active
	def isPLEFilter(self, nFilter):
		return self.nPLEFilter & nFilter != nFilter

	# Sets or toggles a specific filter button (wounded, air, etc) based on the PLE/BUG mode
	def setPLEFilter(self, nFilter, nFilterGroup):
		self.hideInfoPane()
		if (PleOpt.isBugFilterBehavior()):
			bWasSelected = self.isPLEFilter(nFilter)
			# Clear all filters in group
			self.nPLEFilter |= nFilterGroup
			if (not bWasSelected):
				# Select the specified mode
				self.nPLEFilter ^= nFilter
		else:
			# Toggle the specified mode
			self.nPLEFilter ^= nFilter
		CyInterface().setDirty(InterfaceDirtyBits.PlotListButtons_DIRTY_BIT, True)

	# Sets the grouping mode (includes upgrade and promotion modes)
	def setPLEGroupMode(self, nGroupingMode):
		self.hideInfoPane()
		if (self.nPLEGrpMode != nGroupingMode):
			self.nPLEGrpMode = nGroupingMode
			self.setPLEUnitList(True)
			CyInterface().setDirty(InterfaceDirtyBits.PlotListButtons_DIRTY_BIT, True)

	# Sets the view mode
	def setPLEViewMode(self, nViewMode):
		self.hideInfoPane()
		if (self.sPLEMode != nViewMode):
			self.iRowOffset = 0
			self.iColOffset = 0
			self.sPLEMode = nViewMode
			CyInterface().setDirty(InterfaceDirtyBits.PlotListButtons_DIRTY_BIT, True)

	############## input handlers functions ######################

	# Makes the text size small to avoid a scrollbar and displays the help text
	def handleHoverPLEFilter(self, inputClass, sKey, nFilter):
		"Shows or hides the correct hover text for the given filter."
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CURSOR_MOVE_ON ):
			sFullKey = "TXT_KEY_PLE_FILTER_"
			if ( PleOpt.isBugFilterBehavior() ):
				sFullKey += "BUG_"
			sFullKey += sKey
			bSelected = self.isPLEFilter(nFilter)
			if ( bSelected ):
				sFullKey += "_ON"
			self.displayHelpHover(sFullKey)
			return 1
		elif ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CURSOR_MOVE_OFF ):
			self.hideInfoPane()
			return 1
		return 0

	def handleHoverPLEViewMode(self, inputClass, sKey, nViewMode):
		"Shows or hides the hover text for the given view mode."
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CURSOR_MOVE_ON ):
			sFullKey = "TXT_KEY_PLE_MODE_" + sKey
			bSelected = self.sPLEMode == nViewMode
			#if ( bSelected ):
			#	sFullKey += "_ON"
			self.displayHelpHover(sFullKey)
			return 1
		elif ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CURSOR_MOVE_OFF ):
			self.hideInfoPane()
			return 1
		return 0

	def handleHoverPLEGrpMode(self, inputClass, sKey, nGrpMode):
		"Shows or hides the hover text for the given view mode."
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CURSOR_MOVE_ON ):
			sFullKey = "TXT_KEY_PLE_GRP_" + sKey
			if ( sKey == "STANDARD" ):
				bSelected = self.nPLEGrpMode in (self.PLE_GRP_UNITTYPE, self.PLE_GRP_GROUPS)
			elif ( sKey == "PROMO" ):
				bSelected = self.nPLEGrpMode == self.PLE_GRP_PROMO
			elif ( sKey == "UPGRADE" ):
				bSelected = self.nPLEGrpMode == self.PLE_GRP_UPGRADE
			if ( bSelected ):
				sFullKey += "_ON"
			self.displayHelpHover(sFullKey)
			return 1
		elif ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CURSOR_MOVE_OFF ):
			self.hideInfoPane()
			return 1
		return 0



		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			self.setPLEViewMode(self.PLE_MODE_STACK_VERT)
			return 1
		else:
			return self.handleHoverPLEViewMode(inputClass, "STACK_VERT", self.PLE_MODE_STACK_VERT)


	# handles the unit promotion button inputs
	def unitPromotion(self, inputClass):
		id = inputClass.getID()
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CURSOR_MOVE_ON ):
			if not CyInterface().isCityScreenUp():
				self.showPromoInfoPane(id)
			return 1
		elif ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CURSOR_MOVE_OFF ):
			self.hidePromoInfoPane()				
			return 1
		elif ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			self.doPromotion(id)
			CyInterface().setDirty(InterfaceDirtyBits.PlotListButtons_DIRTY_BIT, True)
			return 1

	# Arrow Up
	def getPlotListUpName(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			self.iRowOffset += 1
			CyInterface().setDirty(InterfaceDirtyBits.PlotListButtons_DIRTY_BIT, True)
			return 1
		return 0
		
	# Arrow Down
	def getPlotListDownName(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			if (self.iRowOffset > 0):
				self.iRowOffset -= 1
				CyInterface().setDirty(InterfaceDirtyBits.PlotListButtons_DIRTY_BIT, True)
				return 1
		return 0
		
	# Arrow Left
	def getPlotListMinusName(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			if (self.iColOffset > 0):
				self.iColOffset -= 1
				CyInterface().setDirty(InterfaceDirtyBits.PlotListButtons_DIRTY_BIT, True)
				return 1
		return 0
		
	# Arrow Right
	def getPlotListPlusName(self, inputClass):
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			self.iColOffset += 1
			CyInterface().setDirty(InterfaceDirtyBits.PlotListButtons_DIRTY_BIT, True)
			return 1
		return 0

	# determines the unit button
	def getPlotListButtonName(self, inputClass):
		id = inputClass.getID()
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CURSOR_MOVE_ON ):
			if not CyInterface().isCityScreenUp():
				self.showUnitInfoPane(id)
			if mt.bAlt():
				self.highlightMoves(id)
			return 1
		elif ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CURSOR_MOVE_OFF ):
			self.hideUnitInfoPane()	
			if mt.bAlt():
				self.dehighlightMoves()
			return 1
		elif ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
			# mt.debug("id:%i;p:(%i;%i)"%(id, self.pActPlot.getX(), self.pActPlot.getY()))
			if (id >= 0) and (id <= self.iMaxPlotListIcons):
				self.selectGroup( id, mt.bShift(), mt.bCtrl(), mt.bAlt())
				CyInterface().setDirty(InterfaceDirtyBits.PlotListButtons_DIRTY_BIT, True)
				return 1
		return 0

	# handles the unit upgrade button inputs
	def unitUpgrade(self, inputClass):
		id = inputClass.getID()
		if ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CURSOR_MOVE_ON ):
			if not CyInterface().isCityScreenUp():
				self.showUpgradeInfoPane(id)
			return 1
		elif ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CURSOR_MOVE_OFF ):
			self.hideUpgradeInfoPane()
			return 1
		elif ( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED ):
	#			mt.debug("upgrade id:"+str(id))
			self.doUpgrade(id)
			CyInterface().setDirty(InterfaceDirtyBits.PlotListButtons_DIRTY_BIT, True)
			return 1
		
	############## base functions to calculate/transform the number of objects dependent on the screen resolution ######################

	def getMaxCol(self):
		return ((self.xResolution - (iMultiListXL+iMultiListXR) - 68) / 34)
		
	def getMaxRow(self):
		return ((self.yResolution - 160) / PleOpt.getVerticalSpacing()) 
		
	def getRow(self, i):
		return i / self.getMaxCol()

	def getCol(self, i):
		return i % self.getMaxCol()
		
	def getX(self, nCol):
		return 315 + (nCol * PleOpt.getHoriztonalSpacing())
		
	def getY(self, nRow):
		return self.yResolution - 169 - (nRow * PleOpt.getVerticalSpacing())
		
	def getI(self, nRow, nCol):
		return ( nRow * self.getMaxCol() ) + ( nCol % self.getMaxCol() )

	############## functions for visual objects (show and hide) ######################
		
	# PLE Grouping Mode Switcher 
	def setupPLEGroupModeButtons(self, screen):
		if (self.nPLEGrpMode == self.PLE_GRP_UNITTYPE):
			screen.changeImageButton(self.PLE_GRP_UNITTYPE, ArtFileMgr.getInterfaceArtInfo("PLE_GRP_UNITTYPE").getPath())
			screen.setState(self.PLE_GRP_UNITTYPE, True)
		elif (self.nPLEGrpMode == self.PLE_GRP_GROUPS):
			screen.changeImageButton(self.PLE_GRP_UNITTYPE, ArtFileMgr.getInterfaceArtInfo("PLE_GRP_GROUPS").getPath())
			screen.setState(self.PLE_GRP_UNITTYPE, True)
		else:
			screen.setState(self.PLE_GRP_UNITTYPE, False)
		#screen.setState(self.PLE_GRP_UNITTYPE, self.nPLEGrpMode == self.PLE_GRP_UNITTYPE or self.nPLEGrpMode == self.PLE_GRP_GROUPS)
		#screen.setState(self.PLE_GRP_GROUPS, self.nPLEGrpMode == self.PLE_GRP_GROUPS)
		screen.setState(self.PLE_GRP_PROMO, self.nPLEGrpMode == self.PLE_GRP_PROMO)
		screen.setState(self.PLE_GRP_UPGRADE, self.nPLEGrpMode == self.PLE_GRP_UPGRADE)
		
	# PLE View Mode Switcher
	def setupPLEViewModeButtons(self, screen):
		screen.changeImageButton(self.PLE_VIEW_MODE, ArtFileMgr.getInterfaceArtInfo(self.PLE_VIEW_MODE_ART[self.sPLEMode]).getPath())
	#		screen.setState(self.PLE_MODE_STANDARD, self.sPLEMode == self.PLE_MODE_STANDARD)
	#		screen.setState(self.PLE_MODE_MULTILINE, self.sPLEMode == self.PLE_MODE_MULTILINE)
	#		screen.setState(self.PLE_MODE_STACK_VERT, self.sPLEMode == self.PLE_MODE_STACK_VERT)
	#		screen.setState(self.PLE_MODE_STACK_HORIZ, self.sPLEMode == self.PLE_MODE_STACK_HORIZ)

	# PLE Filters
	def setupPLEFilterButtons(self, screen):
		screen.setState(self.PLE_FILTER_CANMOVE, self.isPLEFilter(self.nPLEFilterModeCanMove))
		screen.setState(self.PLE_FILTER_CANTMOVE, self.isPLEFilter(self.nPLEFilterModeCantMove))
		
		screen.setState(self.PLE_FILTER_NOTWOUND, self.isPLEFilter(self.nPLEFilterModeNotWound))
		screen.setState(self.PLE_FILTER_WOUND, self.isPLEFilter(self.nPLEFilterModeWound))
		
		screen.setState(self.PLE_FILTER_LAND, self.isPLEFilter(self.nPLEFilterModeLand))
		screen.setState(self.PLE_FILTER_SEA, self.isPLEFilter(self.nPLEFilterModeSea))
		screen.setState(self.PLE_FILTER_AIR, self.isPLEFilter(self.nPLEFilterModeAir))

		screen.setState(self.PLE_FILTER_MIL, self.isPLEFilter(self.nPLEFilterModeMil))
		screen.setState(self.PLE_FILTER_DOM, self.isPLEFilter(self.nPLEFilterModeDom))
		
		screen.setState(self.PLE_FILTER_OWN, self.isPLEFilter(self.nPLEFilterModeOwn))
		screen.setState(self.PLE_FILTER_FOREIGN, self.isPLEFilter(self.nPLEFilterModeForeign))
		
		return 0

	# Displays the plot list switches (views, filters, groupings)
	def showPlotListButtonObjects(self, screen):
		if ( PleOpt.isShowButtons() and CyInterface().getShowInterface() != InterfaceVisibility.INTERFACE_HIDE_ALL and CyInterface().getShowInterface() != InterfaceVisibility.INTERFACE_MINIMAP_ONLY and CyInterface().getShowInterface() != InterfaceVisibility.INTERFACE_ADVANCED_START ):
			# show PLE modes switches
			self.setupPLEViewModeButtons(screen)
			screen.show(self.PLE_VIEW_MODE)
	#			screen.show(self.PLE_MODE_STANDARD)
	#			screen.show(self.PLE_MODE_MULTILINE)
	#			screen.show(self.PLE_MODE_STACK_VERT)
	#			screen.show(self.PLE_MODE_STACK_HORIZ)
			
			# show PLE filter switches
			screen.show(self.PLE_RESET_FILTERS)
			
			self.setupPLEFilterButtons(screen)
			screen.show(self.PLE_FILTER_CANMOVE)
			screen.show(self.PLE_FILTER_CANTMOVE)
			
			screen.show(self.PLE_FILTER_NOTWOUND)
			screen.show(self.PLE_FILTER_WOUND)
			
			screen.show(self.PLE_FILTER_LAND)
			screen.show(self.PLE_FILTER_SEA)
			screen.show(self.PLE_FILTER_AIR)
			
			screen.show(self.PLE_FILTER_MIL)
			screen.show(self.PLE_FILTER_DOM)
			
			screen.show(self.PLE_FILTER_OWN)
			screen.show(self.PLE_FILTER_FOREIGN)
			
			# show PLE grouping switches
			self.setupPLEGroupModeButtons(screen)
			screen.show(self.PLE_GRP_UNITTYPE)
			screen.show(self.PLE_GRP_GROUPS)
			screen.show(self.PLE_GRP_PROMO)
			screen.show(self.PLE_GRP_UPGRADE)

			self.bPLEHide = False


	# hides all plot list switches (views, filters, groupings) and all the other objects
	def hidePlotListButtonPLEObjects(self, screen):
		if not self.bPLEHide:
			return

		# hides all unit button objects
		for i in range( self.iMaxPlotListIcons ):
			szString = self.PLOT_LIST_BUTTON_NAME + str(i)
			screen.hide( szString )
			screen.hide( szString + "Icon" )
			screen.hide( szString + "HealthBar" )
			screen.hide( szString + "MoveBar" )
			screen.hide( szString + "PromoFrame" )
			screen.hide( szString + "ActionIcon" )
			screen.hide( szString + "Upgrade" )

		# hides all promotion and upgrade button objects
		for nCol in range(self.getMaxCol()+1):
			for nRow in range(self.getMaxRow()+1):
				# 
				szStringUnitPromo = self.PLOT_LIST_PROMO_NAME + string.zfill(str(nRow), 2) + string.zfill(str(nCol), 2)
				screen.hide( szStringUnitPromo )
				# 
				szStringUnitUpgrade = self.PLOT_LIST_UPGRADE_NAME + string.zfill(str(nRow), 2) + string.zfill(str(nCol), 2)
				screen.hide( szStringUnitUpgrade )
		
		# hide PLE modes switches
		screen.hide(self.PLE_VIEW_MODE)
	#		screen.hide(self.PLE_MODE_STANDARD)
	#		screen.hide(self.PLE_MODE_MULTILINE)
	#		screen.hide(self.PLE_MODE_STACK_VERT)
	#		screen.hide(self.PLE_MODE_STACK_HORIZ)
		# hide horizontal scroll buttons
		screen.hide( self.PLOT_LIST_MINUS_NAME )
		screen.hide( self.PLOT_LIST_PLUS_NAME )
		# hide vertical scroll buttons
		screen.hide( self.PLOT_LIST_UP_NAME )
		screen.hide( self.PLOT_LIST_DOWN_NAME )
		# hide reset all filters button
		screen.hide(self.PLE_RESET_FILTERS)
		# hide PLE filter switches
		screen.hide(self.PLE_FILTER_CANMOVE)
		screen.hide(self.PLE_FILTER_CANTMOVE)
		screen.hide(self.PLE_FILTER_NOTWOUND)
		screen.hide(self.PLE_FILTER_WOUND)
		screen.hide(self.PLE_FILTER_LAND)
		screen.hide(self.PLE_FILTER_SEA)
		screen.hide(self.PLE_FILTER_AIR)
		screen.hide(self.PLE_FILTER_MIL)	
		screen.hide(self.PLE_FILTER_DOM)
		screen.hide(self.PLE_FILTER_OWN)	
		screen.hide(self.PLE_FILTER_FOREIGN)	
		# hide PLE group switches
		screen.hide(self.PLE_GRP_UNITTYPE)	
		screen.hide(self.PLE_GRP_GROUPS)	
		screen.hide(self.PLE_GRP_PROMO)	
		screen.hide(self.PLE_GRP_UPGRADE)	
		
		self.bPLEHide = True
		
	# prepares the display of the mode, view, grouping, filter  switches
	def preparePlotListObjects(self, screen):
		xResolution = self.xResolution
		yResolution = self.yResolution

		iHealthyColor = PleOpt.getHealthyColor()
		iWoundedColor = PleOpt.getWoundedColor()
		iMovementColor = PleOpt.getFullMovementColor()
		iHasMovedColor = PleOpt.getHasMovedColor()
		iNoMovementColor = PleOpt.getNoMovementColor()
		
		szFileNamePromo = ArtFileMgr.getInterfaceArtInfo("OVERLAY_PROMOTION_FRAME").getPath()
		szFileNameGovernor = ArtFileMgr.getInterfaceArtInfo("INTERFACE_BUTTONS_GOVERNOR").getPath()
		szFileNameHilite = ArtFileMgr.getInterfaceArtInfo("BUTTON_HILITE_SQUARE").getPath()
		for i in range( self.iMaxPlotListIcons ):
			# create button name
			szString = self.PLOT_LIST_BUTTON_NAME + str(i)

			x = self.getX( self.getCol( i ) )
			y = self.getY( self.getRow( i ) )

			# place/init the promotion frame. Important to have it at first place within the for loop.
			szStringPromoFrame = szString + "PromoFrame"
			screen.addDDSGFC( szStringPromoFrame, szFileNamePromo, x, y, 32, 32, WidgetTypes.WIDGET_GENERAL, i, -1 )
			screen.hide( szStringPromoFrame )

			# place the plot list unit button
			screen.addCheckBoxGFC( szString, szFileNameGovernor, szFileNameHilite, x, y, 32, 32, WidgetTypes.WIDGET_GENERAL, i, -1, ButtonStyles.BUTTON_STYLE_LABEL )
#tjp			screen.hide( szString )

			# place/init the health bar. Important to have it at last place within the for loop.
			szStringHealthBar = szString + "HealthBar"
#			screen.addStackedBarGFC( szStringHealthBar, x+7, y-7, 25, 14, InfoBarTypes.NUM_INFOBAR_TYPES, WidgetTypes.WIDGET_GENERAL, -1, -1 )
			screen.addStackedBarGFC( szStringHealthBar, x+5, y-9, 29, 11, InfoBarTypes.NUM_INFOBAR_TYPES, WidgetTypes.WIDGET_GENERAL, i, -1 )
			screen.setStackedBarColors( szStringHealthBar, InfoBarTypes.INFOBAR_STORED, iHealthyColor )
			screen.setStackedBarColors( szStringHealthBar, InfoBarTypes.INFOBAR_RATE, iWoundedColor )
			screen.hide( szStringHealthBar )

			# place/init the movement bar. Important to have it at last place within the for loop.
			szStringMoveBar = szString + "MoveBar"
			screen.addStackedBarGFC( szStringMoveBar, x+5, y-5, 29, 11, InfoBarTypes.NUM_INFOBAR_TYPES, WidgetTypes.WIDGET_GENERAL, i, -1 )
			screen.setStackedBarColors( szStringMoveBar, InfoBarTypes.INFOBAR_STORED, iMovementColor )
			screen.setStackedBarColors( szStringMoveBar, InfoBarTypes.INFOBAR_RATE, iHasMovedColor )
			screen.setStackedBarColors( szStringMoveBar, InfoBarTypes.INFOBAR_EMPTY, iNoMovementColor )
			screen.hide( szStringMoveBar )


		nYOff	= 130 + 4
		nXOff	= 290 - 12
		nSize	= 24
		nDist	= 22
		nGap    = 10
		nNum	= 0
		
		# PLE Style-Mode buttons
		#screen.setImageButton( "PleViewModeStyle1", "", 20, 400, 28, 28, WidgetTypes.WIDGET_GENERAL, 1, -1 )
		#screen.setStyle( "PleViewModeStyle1", "Button_BUG_PLE_ViewMode_SingleRow_Style" )
		
		# place the PLE mode switches
		nXOff += nDist
		szString = self.PLE_VIEW_MODE
		screen.addCheckBoxGFC( szString, ArtFileMgr.getInterfaceArtInfo("PLE_MODE_STANDARD").getPath(), "", nXOff, yResolution - nYOff, nSize, nSize, WidgetTypes.WIDGET_GENERAL, 1, -1, ButtonStyles.BUTTON_STYLE_LABEL )
		screen.hide( szString )
		
		# place the PLE grouping mode switches
		nXOff += nDist + nGap
		szString = self.PLE_GRP_UNITTYPE
		screen.addCheckBoxGFC( szString, ArtFileMgr.getInterfaceArtInfo("PLE_GRP_UNITTYPE").getPath(), ArtFileMgr.getInterfaceArtInfo("PLE_BUTTON_HILITE").getPath(), nXOff, yResolution - nYOff, nSize, nSize, WidgetTypes.WIDGET_GENERAL, 1, -1, ButtonStyles.BUTTON_STYLE_LABEL )
		screen.hide( szString )
		
		# place the promotion and upgrades mode switches
		nXOff += nDist
		szString = self.PLE_GRP_PROMO
		screen.addCheckBoxGFC( szString, ArtFileMgr.getInterfaceArtInfo("PLE_GRP_PROMO").getPath(), ArtFileMgr.getInterfaceArtInfo("PLE_BUTTON_HILITE").getPath(), nXOff, yResolution - nYOff, nSize, nSize, WidgetTypes.WIDGET_GENERAL, 1, -1, ButtonStyles.BUTTON_STYLE_LABEL )
		screen.hide( szString )
		
		nXOff += nDist
		szString = self.PLE_GRP_UPGRADE
		screen.addCheckBoxGFC( szString, ArtFileMgr.getInterfaceArtInfo("PLE_GRP_UPGRADE").getPath(), ArtFileMgr.getInterfaceArtInfo("PLE_BUTTON_HILITE").getPath(), nXOff, yResolution - nYOff, nSize, nSize, WidgetTypes.WIDGET_GENERAL, 1, -1, ButtonStyles.BUTTON_STYLE_LABEL )
		screen.hide( szString )
		
		# place the PLE reset filter button
		nXOff += nDist + nGap
		szString = self.PLE_RESET_FILTERS
		screen.addCheckBoxGFC( szString, ArtFileMgr.getInterfaceArtInfo("PLE_RESET_FILTERS").getPath(), "", nXOff, yResolution - nYOff, nSize, nSize, WidgetTypes.WIDGET_GENERAL, -1, -1, ButtonStyles.BUTTON_STYLE_LABEL )
		screen.hide( szString )

		# place the PLE movement filter switches
		nXOff += nDist + nGap
		szString = self.PLE_FILTER_CANMOVE
		screen.addCheckBoxGFC( szString, ArtFileMgr.getInterfaceArtInfo("PLE_FILTER_CANMOVE").getPath(), ArtFileMgr.getInterfaceArtInfo("PLE_BUTTON_HILITE").getPath(), nXOff, yResolution - nYOff, nSize, nSize, WidgetTypes.WIDGET_GENERAL, 1, -1, ButtonStyles.BUTTON_STYLE_LABEL )
		screen.hide( szString )
		
		nXOff += nDist
		szString = self.PLE_FILTER_CANTMOVE
		screen.addCheckBoxGFC( szString, ArtFileMgr.getInterfaceArtInfo("PLE_FILTER_CANTMOVE").getPath(), ArtFileMgr.getInterfaceArtInfo("PLE_BUTTON_HILITE").getPath(), nXOff, yResolution - nYOff, nSize, nSize, WidgetTypes.WIDGET_GENERAL, 1, -1, ButtonStyles.BUTTON_STYLE_LABEL )
		screen.hide( szString )

		# place the PLE health filter switches
		nXOff += nDist + nGap
		szString = self.PLE_FILTER_NOTWOUND
		screen.addCheckBoxGFC( szString, ArtFileMgr.getInterfaceArtInfo("PLE_FILTER_NOTWOUND").getPath(), ArtFileMgr.getInterfaceArtInfo("PLE_BUTTON_HILITE").getPath(), nXOff, yResolution - nYOff, nSize, nSize, WidgetTypes.WIDGET_GENERAL, 1, -1, ButtonStyles.BUTTON_STYLE_LABEL )
		screen.hide( szString )

		nXOff += nDist
		szString = self.PLE_FILTER_WOUND
		screen.addCheckBoxGFC( szString, ArtFileMgr.getInterfaceArtInfo("PLE_FILTER_WOUND").getPath(), ArtFileMgr.getInterfaceArtInfo("PLE_BUTTON_HILITE").getPath(), nXOff, yResolution - nYOff, nSize, nSize, WidgetTypes.WIDGET_GENERAL, 1, -1, ButtonStyles.BUTTON_STYLE_LABEL )
		screen.hide( szString )

		# place the PLE domain filter switches
		nXOff += nDist + nGap
		szString = self.PLE_FILTER_LAND
		screen.addCheckBoxGFC( szString, ArtFileMgr.getInterfaceArtInfo("PLE_FILTER_LAND").getPath(), ArtFileMgr.getInterfaceArtInfo("PLE_BUTTON_HILITE").getPath(), nXOff, yResolution - nYOff, nSize, nSize, WidgetTypes.WIDGET_GENERAL, 1, -1, ButtonStyles.BUTTON_STYLE_LABEL )
		screen.hide( szString )

		nXOff += nDist
		szString = self.PLE_FILTER_SEA
		screen.addCheckBoxGFC( szString, ArtFileMgr.getInterfaceArtInfo("PLE_FILTER_SEA").getPath(), ArtFileMgr.getInterfaceArtInfo("PLE_BUTTON_HILITE").getPath(), nXOff, yResolution - nYOff, nSize, nSize, WidgetTypes.WIDGET_GENERAL, 1, -1, ButtonStyles.BUTTON_STYLE_LABEL )
		screen.hide( szString )

		nXOff += nDist
		szString = self.PLE_FILTER_AIR
		screen.addCheckBoxGFC( szString, ArtFileMgr.getInterfaceArtInfo("PLE_FILTER_AIR").getPath(), ArtFileMgr.getInterfaceArtInfo("PLE_BUTTON_HILITE").getPath(), nXOff, yResolution - nYOff, nSize, nSize, WidgetTypes.WIDGET_GENERAL, 1, -1, ButtonStyles.BUTTON_STYLE_LABEL )
		screen.hide( szString )

		# place the PLE civilian/military filter switches
		nXOff += nDist + nGap
		szString = self.PLE_FILTER_MIL
		screen.addCheckBoxGFC( szString, ArtFileMgr.getInterfaceArtInfo("PLE_FILTER_MIL").getPath(), ArtFileMgr.getInterfaceArtInfo("PLE_BUTTON_HILITE").getPath(), nXOff, yResolution - nYOff, nSize, nSize, WidgetTypes.WIDGET_GENERAL, 1, -1, ButtonStyles.BUTTON_STYLE_LABEL )
		screen.hide( szString )
		
		nXOff += nDist
		szString = self.PLE_FILTER_DOM
		screen.addCheckBoxGFC( szString, ArtFileMgr.getInterfaceArtInfo("PLE_FILTER_DOM").getPath(), ArtFileMgr.getInterfaceArtInfo("PLE_BUTTON_HILITE").getPath(), nXOff, yResolution - nYOff, nSize, nSize, WidgetTypes.WIDGET_GENERAL, 1, -1, ButtonStyles.BUTTON_STYLE_LABEL )
		screen.hide( szString )
				
		# place the PLE owner filter switches
		nXOff += nDist + nGap
		szString = self.PLE_FILTER_OWN
		screen.addCheckBoxGFC( szString, ArtFileMgr.getInterfaceArtInfo("PLE_FILTER_OWN").getPath(), ArtFileMgr.getInterfaceArtInfo("PLE_BUTTON_HILITE").getPath(), nXOff, yResolution - nYOff, nSize, nSize, WidgetTypes.WIDGET_GENERAL, 1, -1, ButtonStyles.BUTTON_STYLE_LABEL )
		screen.hide( szString )
		
		nXOff += nDist
		szString = self.PLE_FILTER_FOREIGN
		screen.addCheckBoxGFC( szString, ArtFileMgr.getInterfaceArtInfo("PLE_FILTER_FOREIGN").getPath(), ArtFileMgr.getInterfaceArtInfo("PLE_BUTTON_HILITE").getPath(), nXOff, yResolution - nYOff, nSize, nSize, WidgetTypes.WIDGET_GENERAL, 1, -1, ButtonStyles.BUTTON_STYLE_LABEL )
		screen.hide( szString )
				
	################ functions for normal/shift/ctrl/alt unit selection within the plot list itself #################

	# deselects all units in the plot list
	def deselectAll(self):
		for i in range(len(self.lPLEUnitList)):
			pUnit = self.getInterfacePlotUnit(i)
			if (pUnit.IsSelected()):
				CyInterface().selectUnit(pUnit, False, True, False)	

	# function saves all units not matching actual filter criteria in a temp list by type
	def saveFilteredUnitsByType(self, pCompareUnit, bShift):
		self.lPLEUnitListTempOK = []
		self.lPLEUnitListTempNOK = []
		# save unit type for comparision
		pCompareUnitType = pCompareUnit.getUnitType()
		for i in range(len(self.lPLEUnitList)):
			pLoopUnit = self.getInterfacePlotUnit(i)
			# has the unit the correct type and does the unit NOT match the filter parameters
			if (pLoopUnit.getUnitType() == pCompareUnitType) and (not (self.checkDisplayFilter(pLoopUnit))):
				# unit has to be moved
				self.lPLEUnitListTempNOK.append(pLoopUnit)
			else:
				# unit has to be displayed
				self.lPLEUnitListTempOK.append(pLoopUnit)
		# loop to find all the cargo of units in the OK list. They don't have to be moved away.
		lTempNOK 	= self.lPLEUnitListTempNOK[:]
		lTempOK 	= self.lPLEUnitListTempOK[:]
		for pLoopUnitNOK in lTempNOK:
			# check if unit is cargo
			if pLoopUnitNOK.isCargo():
				# check if the units transport unit is a to be displayed unit
				for pLoopUnitOK in lTempOK:
					if pLoopUnitOK.getID() == pLoopUnitNOK.getTransportUnit().getID():
						# remove cargo unit from NOK array and append it to OK array
						self.lPLEUnitListTempNOK.remove(pLoopUnitNOK)
						self.lPLEUnitListTempOK.append(pLoopUnitNOK)
		# if Shift is pressed, we also have to keep the already selected units 
		if bShift:
			lTempNOK 	= self.lPLEUnitListTempNOK[:]
			lTempOK 	= self.lPLEUnitListTempOK[:]
			for i in range(len(self.lPLEUnitList)):
				pLoopUnit = self.getInterfacePlotUnit(i)
				if (pLoopUnit.IsSelected()):
					if pLoopUnit in lTempNOK:
						self.lPLEUnitListTempNOK.remove(pLoopUnitNOK)
						self.lPLEUnitListTempOK.append(pLoopUnitNOK)
						
					
	# function saves all units not matching actual filter criteria in a temp list by domain
	def saveFilteredUnitsByDomain(self, pCompareUnit):
		self.lPLEUnitListTempOK = []
		self.lPLEUnitListTempNOK = []
		# save unit type for comparision
		pUnitTypeInfo = gc.getUnitInfo(pCompareUnit.getUnitType())
		eCompareDomain = pUnitTypeInfo.getDomainType()
		for i in range(len(self.lPLEUnitList)):
			pLoopUnit = self.getInterfacePlotUnit(i)
			pUnitTypeInfo = gc.getUnitInfo(pLoopUnit.getUnitType())
			eDomainType = pUnitTypeInfo.getDomainType()
			# has the unit the correct domain and ismatching the current filter criteria
			if (eDomainType == eCompareDomain) and (self.checkDisplayFilter(pLoopUnit)):					
				# unit has to be displayed
				self.lPLEUnitListTempOK.append(pLoopUnit)
			else:
				# unit has to be moved
				self.lPLEUnitListTempNOK.append(pLoopUnit)
		# loop to find all the cargo of units in the OK list. They don't have to be moved away.
		lTempNOK 	= self.lPLEUnitListTempNOK[:]
		lTempOK 	= self.lPLEUnitListTempOK[:]
		for pLoopUnitNOK in lTempNOK:
			# check if unit is cargo
			if pLoopUnitNOK.isCargo():
				# check if the units transport unit is a to be displayed unit
				for pLoopUnitOK in lTempOK:
					if pLoopUnitOK.getID() == pLoopUnitNOK.getTransportUnit().getID():
						# remove cargo unit from NOK array and append it to OK array
						self.lPLEUnitListTempNOK.remove(pLoopUnitNOK)
						self.lPLEUnitListTempOK.append(pLoopUnitNOK)

	# finds plots where we can temporarily park some units.
	# the "parking" is needed to avoid that the units are selected by the CyInterface.selectGroup() function.
	def getTempPlot(self):
		# first try : put them into another city
		pPlayer = gc.getActivePlayer()
		iPlayer = CyGame().getActivePlayer()
		lCity = PyPlayer(iPlayer).getCityList()
		pPlot = CyMap().plot(0,0)
		dPlotList = {}
		if not (self.pActPlot.isCity()):
			# if actual plot is not a city -> use first available city to park units
			pPlot = lCity[0].plot()
			for d in range(DomainTypes.NUM_DOMAIN_TYPES):
				dPlotList[d] = pPlot
		elif (pPlayer.getNumCities() > 1):
			# if actual plot is a city -> use next available city to park units
			for i in range(pPlayer.getNumCities()):
				pPlot =  lCity[i].plot()
				if (pPlot.getX() != self.pActPlot.getX()) or (pPlot.getY() != self.pActPlot.getY()):
					break
			for d in range(DomainTypes.NUM_DOMAIN_TYPES):
				dPlotList[d] = pPlot
		else:
			# no city available -> place units around the capital. There is the smallest chance to reveal a plot.
			lList = []
			pCapital = PyPlayer(iPlayer).getCapitalCity()
			for dx in range(-1, 2):
				for dy in range(-1, 2):
					if dx != 0 and dy != 0:
						pPlot = CyMap().plot(pCapital.getX()+dx, pCapital.getY()+dy)
						lList.append(pPlot)
			for d in range(DomainTypes.NUM_DOMAIN_TYPES):
				dPlotList[d] = lList[d]
		return dPlotList
			
	# temporarily moves a unit away, so that the select group works well.
	def tempMove(self, iMode):
		if iMode == 0:
			dTempPlots = self.getTempPlot()
		for i in range(len(self.lPLEUnitListTempNOK)):
			pLoopUnit = self.lPLEUnitListTempNOK[i]
			eDomainType = gc.getUnitInfo(pLoopUnit.getUnitType()).getDomainType()
			# move unit to temp plot. 
			if iMode == 0:
				pTempPlot = dTempPlots[eDomainType]
				pLoopUnit.setXY( pTempPlot.getX(), pTempPlot.getY(), False, True, False )
			else:
				pLoopUnit.setXY( self.pActPlot.getX(), self.pActPlot.getY(), False, True, False )

	# replacement of the civ 4 version
	def selectGroup(self, iID, bShift, bCtrl, bAlt):
		pUnit = self.listPLEButtons[iID][0]
		# check if the unit has been selected from the city screen
		bCityUp = CyInterface().isCityScreenUp()
		if not (self.pActPlotListUnit):
			self.pActPlotListUnit = CyInterface().getHeadSelectedUnit()
			self.pActPlotListGroup = self.pActPlotListUnit.getGroupID()
		if (not (bShift or bCtrl or bAlt)):
	#			# save prev selections
	#			self.pLastPlotListUnit = self.pActPlotListUnit
	#			self.iLastPlotListGroup = self.pActPlotListUnit.getGroupID()
			# save act selection
			self.pActPlotListUnit = pUnit
			self.iActPlotListGroup = pUnit.getGroupID()
			CyInterface().selectGroup( self.pActPlotListUnit, false, false, false )
	#			# check if the group has been changed 
	#			if (self.iLastPlotListGroup != self.iActPlotListGroup):
	#				self.deselectAll()
	#			# deselect last selected unit
	#			elif (self.pLastPlotListUnit):
	#				if (self.pLastPlotListUnit.IsSelected()):
	#					CyInterface().selectUnit(self.pLastPlotListUnit, false, true, false)
	#			# check if the group has not been changed and the unit is selected again -> deselect all other units of the group
	#			if (self.iLastPlotListGroup == self.iActPlotListGroup):
	#				CyInterface().selectUnit(self.pActPlotListUnit, true, true, true)
	#			else:
	#				CyInterface().selectUnit(self.pActPlotListUnit, false, true, true)
		elif bShift and (not (bCtrl or bAlt)):
			self.pActPlotListUnit = pUnit
			self.iActPlotListGroup = pUnit.getGroupID()
	#			CyInterface().selectUnit(self.pActPlotListUnit, false, true, true)
			CyInterface().selectGroup( self.pActPlotListUnit, true, false, false )
		elif bCtrl and (not (bShift or bAlt)):
			self.deselectAll()
			self.pActPlotListUnit = pUnit
			self.iActPlotListGroup = pUnit.getGroupID()
			self.saveFilteredUnitsByType(self.pActPlotListUnit, false)
			self.tempMove(0)
			CyInterface().selectGroup( self.pActPlotListUnit, false, true, false )
			self.tempMove(1)
			self.setPLEUnitList(True)
		elif bCtrl and bShift and (not bAlt):
	#			# self.deselectAll()
			self.pActPlotListUnit = pUnit
			self.iActPlotListGroup = pUnit.getGroupID()
			self.saveFilteredUnitsByType(self.pActPlotListUnit, true)
			self.tempMove(0)
			CyInterface().selectGroup( self.pActPlotListUnit, true, true, false )
			self.tempMove(1)
			self.setPLEUnitList(True)
		elif bAlt and (not (bCtrl or bShift)):
			self.deselectAll()
			self.pActPlotListUnit = pUnit
			self.iActPlotListGroup = pUnit.getGroupID()
			self.saveFilteredUnitsByDomain(self.pActPlotListUnit)
			self.tempMove(0)
			CyInterface().selectGroup( self.pActPlotListUnit, false, false, true )
			self.tempMove(1)
			self.setPLEUnitList(True)
		# if we came from city screen -> focus view on the selected unit
		if bCityUp:
			CyCamera().JustLookAtPlot(self.pActPlot)

	################## general PLE functions ##################

	# resets the colors of the plot list stacked bars
	def resetUnitPlotListStackedBarColors( self ):
		screen = CyGInterfaceScreen( "MainInterface", CvScreenEnums.MAIN_INTERFACE )
		iHealthyColor = PleOpt.getHealthyColor()
		iWoundedColor = PleOpt.getWoundedColor()
		iMovementColor = PleOpt.getFullMovementColor()
		iHasMovedColor = PleOpt.getHasMovedColor()
		iNoMovementColor = PleOpt.getNoMovementColor()
		for i in range( self.iMaxPlotListIcons ):
			# create button name
			szString = self.PLOT_LIST_BUTTON_NAME + str(i)

			szStringHealthBar = szString + "HealthBar"
			screen.setStackedBarColors( szStringHealthBar, InfoBarTypes.INFOBAR_STORED, iHealthyColor )
			screen.setStackedBarColors( szStringHealthBar, InfoBarTypes.INFOBAR_RATE, iWoundedColor )

			# place/init the movement bar. Important to have it at last place within the for loop.
			szStringMoveBar = szString + "MoveBar"
			screen.setStackedBarColors( szStringMoveBar, InfoBarTypes.INFOBAR_STORED, iMovementColor )
			screen.setStackedBarColors( szStringMoveBar, InfoBarTypes.INFOBAR_RATE, iHasMovedColor )
			screen.setStackedBarColors( szStringMoveBar, InfoBarTypes.INFOBAR_EMPTY, iNoMovementColor )

	# displays a single unit icon in the plot list with all its decorations
	def displayUnitPlotListObjects( self, screen, pLoopUnit, nRow, nCol ):
		iCount = self.getI(nRow, nCol)
		self.listPLEButtons[iCount] = ( pLoopUnit, nRow, nCol )
		self.bPLEHide = False

		x = self.getX( nCol )
		y = self.getY( nRow )

		# create the button name 
		szString = self.PLOT_LIST_BUTTON_NAME + str(iCount)

		# set unit button image
		screen.changeImageButton( szString, gc.getUnitInfo(pLoopUnit.getUnitType()).getButton() )

		# check if it is an player unit or not
		if ( pLoopUnit.getOwner() == gc.getGame().getActivePlayer() ):
			bEnable = True
		else:
			bEnable = False
		# if player unit enable button (->visible, but not selectable)
		screen.enable(szString, bEnable)

		# check if the units is selected
		if (pLoopUnit.IsSelected()):
			screen.setState(szString, True)
		else:
			screen.setState(szString, False)
		# set select state of the unit button
		screen.show( szString )

		if bEnable:
			self.displayUnitPlotList_Dot( screen, pLoopUnit, szString, iCount, x, y )
			self.displayUnitPlotList_Promo( screen, pLoopUnit, szString )
			self.displayUnitPlotList_Upgrade( screen, pLoopUnit, szString, iCount, x, y )
			self.displayUnitPlotList_HealthBar( screen, pLoopUnit, szString )
			self.displayUnitPlotList_MoveBar( screen, pLoopUnit, szString )
			self.displayUnitPlotList_Mission( screen, pLoopUnit, szString, iCount, x, y, 16 )

		return 0

	def UnitPlotList_BUGOptions(self):
		self.bShowWoundedIndicator = PleOpt.isShowWoundedIndicator()
		self.bShowGreatGeneralIndicator = PleOpt.isShowGreatGeneralIndicator()
		self.bShowPromotionIndicator = PleOpt.isShowPromotionIndicator()
		self.bShowUpgradeIndicator = PleOpt.isShowUpgradeIndicator()
		self.bShowMissionInfo = PleOpt.isShowMissionInfo()
		self.bShowHealthBar = PleOpt.isShowHealthBar()
		self.bHideHealthBarWhileFighting = PleOpt.isHideHealthFighting()
		self.bShowMoveBar = PleOpt.isShowMoveBar()

	def displayUnitPlotList_Dot( self, screen, pLoopUnit, szString, iCount, x, y ):
		# this if statement and everything inside, handles the display of the colored buttons in the upper left corner of each unit icon.
		xSize = 12
		ySize = 12
		xOffset = 0
		yOffset = 0
		if ((pLoopUnit.getTeam() != gc.getGame().getActiveTeam()) or pLoopUnit.isWaiting()):
			# fortified
			szDotState = "OVERLAY_FORTIFY"
		elif (pLoopUnit.canMove()):
			if (pLoopUnit.hasMoved()):
				# unit moved, but some movement points are left
				szDotState = "OVERLAY_HASMOVED"
			else:
				# unit did not move yet
				szDotState = "OVERLAY_MOVE"
		else:
			# unit has no movement points left
			szDotState = "OVERLAY_NOMOVE"

		# Wounded units will get a darker colored button.
		if (self.bShowWoundedIndicator) and (pLoopUnit.isHurt()):
			szDotState += "_INJURED"

		# Units lead by a GG will get a star instead of a dot.
		if (self.bShowGreatGeneralIndicator):
			# is unit lead by a GG?
			iLeaderPromo = gc.getInfoTypeForString('PROMOTION_LEADER')
			if (iLeaderPromo != -1 and pLoopUnit.isHasPromotion(iLeaderPromo)):
				szDotState += "_GG"
				xSize = 16
				ySize = 16
				xOffset = -3
				yOffset = -3

		szFileNameState = ArtFileMgr.getInterfaceArtInfo(szDotState).getPath()

		# display the colored spot icon
		szStringIcon = szString+"Icon"
		screen.addDDSGFC( szStringIcon, szFileNameState, x-3+xOffset, y-7+yOffset, xSize, ySize, WidgetTypes.WIDGET_GENERAL, iCount, -1 )
		screen.show( szStringIcon )

		return 0

	def displayUnitPlotList_Promo( self, screen, pLoopUnit, szString ):
		if (self.bShowPromotionIndicator):
			# can unit be promoted ?
			if (pLoopUnit.isPromotionReady()):
				# place the promotion frame
				szStringPromoFrame = szString+"PromoFrame"
				screen.show( szStringPromoFrame )

		return 0

	def displayUnitPlotList_Upgrade( self, screen, pLoopUnit, szString, iCount, x, y ):
		if (self.bShowUpgradeIndicator):
			# can unit be upgraded ?
			if (mt.checkAnyUpgrade(pLoopUnit)):
				# place the upgrade arrow
				szStringUpgrade = szString+"Upgrade"
				szFileNameUpgrade = ArtFileMgr.getInterfaceArtInfo("OVERLAY_UPGRADE").getPath()	
				screen.addDDSGFC( szStringUpgrade, szFileNameUpgrade, x+2, y+14, 8, 16, WidgetTypes.WIDGET_GENERAL, iCount, -1 )
				screen.show( szStringUpgrade )

		return 0

	def displayUnitPlotList_HealthBar( self, screen, pLoopUnit, szString ):
		if (self.bShowHealthBar and pLoopUnit.maxHitPoints()
		and not (pLoopUnit.isFighting() and self.bHideHealthBarWhileFighting)):
			# place the health bar
			szStringHealthBar = szString+"HealthBar"
			screen.setBarPercentage( szStringHealthBar, InfoBarTypes.INFOBAR_STORED, float( pLoopUnit.currHitPoints() ) / float( pLoopUnit.maxHitPoints() ) )
			screen.setBarPercentage( szStringHealthBar, InfoBarTypes.INFOBAR_RATE, float(1.0) )

			# EF: Colors are set by user instead
			#if (pLoopUnit.getDamage() >= ((pLoopUnit.maxHitPoints() * 2) / 3)):
			#	screen.setStackedBarColors(szStringHealthBar, InfoBarTypes.INFOBAR_STORED, gc.getInfoTypeForString("COLOR_RED"))
			#elif (pLoopUnit.getDamage() >= (pLoopUnit.maxHitPoints() / 3)):
			#	screen.setStackedBarColors(szStringHealthBar, InfoBarTypes.INFOBAR_STORED, gc.getInfoTypeForString("COLOR_YELLOW"))
			#else:
			#	screen.setStackedBarColors(szStringHealthBar, InfoBarTypes.INFOBAR_STORED, gc.getInfoTypeForString("COLOR_GREEN"))	

			screen.show( szStringHealthBar )

		return 0

	def displayUnitPlotList_MoveBar( self, screen, pLoopUnit, szString ):
		if (self.bShowMoveBar):
			# place the move bar
			szStringMoveBar = szString+"MoveBar"
			if (pLoopUnit.movesLeft() == 0 or pLoopUnit.baseMoves() == 0):
				screen.setBarPercentage( szStringMoveBar, InfoBarTypes.INFOBAR_STORED, 0.0 )
				screen.setBarPercentage( szStringMoveBar, InfoBarTypes.INFOBAR_RATE, 0.0 )
				screen.setBarPercentage( szStringMoveBar, InfoBarTypes.INFOBAR_EMPTY, 1.0 )
			else:
				fMaxMoves = float(pLoopUnit.baseMoves())
				#fCurrMoves = fMaxMoves - (pLoopUnit.getMoves() / float(gc.getMOVE_DENOMINATOR())) 
				fCurrMoves = float(pLoopUnit.movesLeft()) / float(gc.getMOVE_DENOMINATOR()) 
				# mt.debug("c/m/r:%f/%f/%f"%(fCurrMoves, fMaxMoves, float( fCurrMoves ) / float( fMaxMoves ) ))
				if (fMaxMoves):
					screen.setBarPercentage( szStringMoveBar, InfoBarTypes.INFOBAR_STORED, fCurrMoves / fMaxMoves )
				else:
					screen.setBarPercentage( szStringMoveBar, InfoBarTypes.INFOBAR_STORED, 1.0 )
				screen.setBarPercentage( szStringMoveBar, InfoBarTypes.INFOBAR_RATE, 1.0 )
				screen.setBarPercentage( szStringMoveBar, InfoBarTypes.INFOBAR_EMPTY, 1.0 )
			screen.show( szStringMoveBar )

		return 0

	def displayUnitPlotList_Mission( self, screen, pLoopUnit, szString, iCount, x, y, iSize ):
		# display the mission or activity info
		if (self.bShowMissionInfo): 
			# TODO: Switch to UnitUtil.getOrder()
			# place the activity info below the unit icon.
			szFileNameAction = ""
			eActivityType = pLoopUnit.getGroup().getActivityType()
			eAutomationType = pLoopUnit.getGroup().getAutomateType()

			# is unit on air intercept mission
			if (eActivityType == ActivityTypes.ACTIVITY_INTERCEPT):
				szFileNameAction = ArtFileMgr.getInterfaceArtInfo("OVERLAY_ACTION_INTERCEPT").getPath()
			# is unit on boat patrol coast mission
			elif (eActivityType == ActivityTypes.ACTIVITY_PATROL):
				szFileNameAction = ArtFileMgr.getInterfaceArtInfo("OVERLAY_ACTION_PATROL").getPath()
			# is unit on boat blockade mission
			elif (eActivityType == ActivityTypes.ACTIVITY_PLUNDER):
				szFileNameAction = ArtFileMgr.getInterfaceArtInfo("OVERLAY_ACTION_PLUNDER").getPath()
			# is unit fortified for healing (wake up when healed)
			elif (eActivityType == ActivityTypes.ACTIVITY_HEAL):
				szFileNameAction = ArtFileMgr.getInterfaceArtInfo("OVERLAY_ACTION_HEAL").getPath()
			# is unit sentry (wake up when enemy in sight)
			elif (eActivityType == ActivityTypes.ACTIVITY_SENTRY):
				szFileNameAction = ArtFileMgr.getInterfaceArtInfo("OVERLAY_ACTION_SENTRY").getPath()
			# is the turn for this unit skipped (wake up next turn)
			elif (eActivityType == ActivityTypes.ACTIVITY_HOLD):
				szFileNameAction = ArtFileMgr.getInterfaceArtInfo("OVERLAY_ACTION_SKIP").getPath()
			# has unit exploration mission
			elif (eAutomationType == AutomateTypes.AUTOMATE_EXPLORE):
				szFileNameAction = ArtFileMgr.getInterfaceArtInfo("OVERLAY_ACTION_EXPLORE").getPath()
			# is unit automated generally (only worker units)
			elif (eAutomationType == AutomateTypes.AUTOMATE_BUILD):
				szFileNameAction = ArtFileMgr.getInterfaceArtInfo("OVERLAY_ACTION_AUTO_BUILD").getPath()
			# is unit automated for nearest city (only worker units)
			elif (eAutomationType == AutomateTypes.AUTOMATE_CITY):
				szFileNameAction = ArtFileMgr.getInterfaceArtInfo("OVERLAY_ACTION_AUTO_CITY").getPath()
			# is unit automated for network (only worker units)
			elif (eAutomationType == AutomateTypes.AUTOMATE_NETWORK):
				szFileNameAction = ArtFileMgr.getInterfaceArtInfo("OVERLAY_ACTION_AUTO_NETWORK").getPath()
			# is unit automated spread religion (only missionary units)
			elif (eAutomationType == AutomateTypes.AUTOMATE_RELIGION):
				szFileNameAction = ArtFileMgr.getInterfaceArtInfo("OVERLAY_ACTION_AUTO_RELIGION").getPath()
			# has unit a mission
			elif (pLoopUnit.getGroup().getLengthMissionQueue() > 0):
				eMissionType = pLoopUnit.getGroup().getMissionType(0)
				# is the mission to build an improvement
				if (eMissionType == MissionTypes.MISSION_BUILD):
					szFileNameAction = ArtFileMgr.getInterfaceArtInfo("OVERLAY_ACTION_BUILD").getPath()
				# is the mission a "move to" mission
				elif (eMissionType in UnitUtil.MOVE_TO_MISSIONS):
					szFileNameAction = ArtFileMgr.getInterfaceArtInfo("OVERLAY_ACTION_GOTO").getPath()
			# if nothing of above, but unit is waiting -> unit is fortified
			elif (pLoopUnit.isWaiting()):
				if (pLoopUnit.isFortifyable()):
					szFileNameAction = ArtFileMgr.getInterfaceArtInfo("OVERLAY_ACTION_FORTIFY").getPath()
				else:
					szFileNameAction = ArtFileMgr.getInterfaceArtInfo("OVERLAY_ACTION_SLEEP").getPath()

			# display the mission icon
			if (szFileNameAction != ""):
				szStringActionIcon = szString+"ActionIcon"
				screen.addDDSGFC( szStringActionIcon, szFileNameAction, x+20, y+20, iSize, iSize, WidgetTypes.WIDGET_GENERAL, iCount, -1 )
				screen.show( szStringActionIcon )

		return 0

	# checks if the unit matches actual filter conditions
	def checkDisplayFilter(self, pUnit):

		# in case of Promotion or Upgrade Display 
		if (self.nPLEGrpMode == self.PLE_GRP_PROMO):
			# if unit is not promotion ready -> return
			if not pUnit.isPromotionReady():
				return False
		elif (self.nPLEGrpMode == self.PLE_GRP_UPGRADE):
			# if unit is not upgrade ready -> return
			if not mt.checkAnyUpgrade(pUnit):
				return False
		elif pUnit.isCargo():
			# in case the unit is a cargo unit, the decision is made by the tranporting unit. 
			# that ensures, that cargo is always displayed or not displayed together with its tranporting unit
			return self.checkDisplayFilter(pUnit.getTransportUnit())
		
		if (self.isPLEFilter(self.nPLEAllFilters)):
			# At least one filter is active
			if (PleOpt.isPleFilterBehavior()):
				# unit can move and filter active
				if (self.isPLEFilter(self.nPLEFilterModeCanMove)):
					if (pUnit.movesLeft()):
						return False
				# unit cannot move and filter active
				if (self.isPLEFilter(self.nPLEFilterModeCantMove)):
					if (not pUnit.movesLeft()):
						return False
				
				# unit not wounded and filter active
				if (self.isPLEFilter(self.nPLEFilterModeNotWound)):
					if (not pUnit.isHurt()):
						return False
				# unit wounded and filter active
				if (self.isPLEFilter(self.nPLEFilterModeWound)):
					if (pUnit.isHurt()):
						return False
				
				pUnitTypeInfo = gc.getUnitInfo(pUnit.getUnitType())
				# is unit a land unit (or ICBM) and filter active
				if (self.isPLEFilter(self.nPLEFilterModeLand)):
					if (pUnitTypeInfo.getDomainType() == DomainTypes.DOMAIN_LAND) or (pUnitTypeInfo.getDomainType() == DomainTypes.DOMAIN_IMMOBILE):
						return False
				# is unit a sea unit and filter active
				if (self.isPLEFilter(self.nPLEFilterModeSea)):
					if (pUnitTypeInfo.getDomainType() == DomainTypes.DOMAIN_SEA):
						return False
				# is unit a air unit and filter active
				if (self.isPLEFilter(self.nPLEFilterModeAir)):
					if (pUnitTypeInfo.getDomainType() == DomainTypes.DOMAIN_AIR):
						return False
				
				# is unit a combat unit and filter active (combat means -> Combat or AirCombat values > 0!
				if (self.isPLEFilter(self.nPLEFilterModeMil)):
					if ((pUnitTypeInfo.getCombat() > 0) or (pUnitTypeInfo.getAirCombat() > 0)):
						return False
				# is unit a domestic unit and filter active (domestic means -> no Combat or AirCombat values!
				if (self.isPLEFilter(self.nPLEFilterModeDom)):
					if ((pUnitTypeInfo.getCombat() == 0) and (pUnitTypeInfo.getAirCombat() == 0)):
						return False
				
				# is the units owner the active player
				if (self.isPLEFilter(self.nPLEFilterModeOwn)):
					if ( pUnit.getOwner() == gc.getGame().getActivePlayer() ):
						return False
				# # is the units owner another player
				if (self.isPLEFilter(self.nPLEFilterModeForeign)):
					if ( not ( pUnit.getOwner() == gc.getGame().getActivePlayer() )):
						return False
			else:
				# BUG Filter Mode
				if (self.isPLEFilter(self.nPLEFilterModeCanMove)):
					if (not pUnit.movesLeft()):
						return False
				elif (self.isPLEFilter(self.nPLEFilterModeCantMove)):
					if (pUnit.movesLeft()):
						return False
				
				if (self.isPLEFilter(self.nPLEFilterModeNotWound)):
					if (pUnit.isHurt()):
						return False
				elif (self.isPLEFilter(self.nPLEFilterModeWound)):
					if (not pUnit.isHurt()):
						return False
				
				pUnitTypeInfo = gc.getUnitInfo(pUnit.getUnitType())
				if (self.isPLEFilter(self.nPLEFilterModeLand)):
					if (pUnitTypeInfo.getDomainType() != DomainTypes.DOMAIN_LAND) and (gc.getUnitInfo(pUnit.getUnitType()).getDomainType() != DomainTypes.DOMAIN_IMMOBILE):
						return False
				elif (self.isPLEFilter(self.nPLEFilterModeSea)):
					if (pUnitTypeInfo.getDomainType() != DomainTypes.DOMAIN_SEA):
						return False
				elif (self.isPLEFilter(self.nPLEFilterModeAir)):
					if (pUnitTypeInfo.getDomainType() != DomainTypes.DOMAIN_AIR):
						return False
				
				if (self.isPLEFilter(self.nPLEFilterModeMil)):
					if ((pUnitTypeInfo.getCombat() == 0) and (pUnitTypeInfo.getAirCombat() == 0)):
						return False
				elif (self.isPLEFilter(self.nPLEFilterModeDom)):
					if ((pUnitTypeInfo.getCombat() > 0) or (pUnitTypeInfo.getAirCombat() > 0)):
						return False
				
				if (self.isPLEFilter(self.nPLEFilterModeOwn)):
					if ( pUnit.getOwner() != gc.getGame().getActivePlayer() ):
						return False
				elif (self.isPLEFilter(self.nPLEFilterModeForeign)):
					if ( pUnit.getOwner() == gc.getGame().getActivePlayer() ):
						return False
		
		return True
		
	# create an info set for each unit. This set is used to determine the order of the plot list buttons.
	def getPLEUnitInfo(self, pUnit):
		if pUnit.isCargo() and (self.nPLEGrpMode != self.PLE_GRP_PROMO) and (self.nPLEGrpMode != self.PLE_GRP_UPGRADE):
			# if unit is cargo, we do retrieve the transport units characteristics to insert the cargo unit behind the transport unit in the sort list.
			pTransportUnit = pUnit.getTransportUnit()
			setUnit = self.getPLEUnitInfo(pTransportUnit)
			tReturn = (setUnit[self.IDX_PLAYER], setUnit[self.IDX_DOMAIN], setUnit[self.IDX_GROUPID], setUnit[self.IDX_COMBAT], setUnit[self.IDX_UNITTYPE], setUnit[self.IDX_LEVEL], setUnit[self.IDX_XP], pTransportUnit.getID(), pUnit.getID(), pUnit.getID(), pUnit)
			return tReturn
		else:
			# retrieve player info
			iPlayer = pUnit.getOwner()
			# get gproup id of the unit. only when display mode = group
			if (self.nPLEGrpMode == self.PLE_GRP_GROUPS):
				if (pUnit.getGroup().getNumUnits() > 1):
					iGroupID = pUnit.getGroupID()
				else:
					iGroupID = 0
			else:
				iGroupID = 0
			# retrieve domain info
			pUnitTypeInfo = gc.getUnitInfo(pUnit.getUnitType())
			eDomainType = pUnitTypeInfo.getDomainType()
			# retrieve combat strength :
			# - baseCombat is only set for ground units
			# - airBaseCombat is set used for ait units
			# - bombardRate is only set for Artillery 
			# - bombRate is only set for Bombers
			# the following calculation makes artillery/bombers listed before tanks/fighters
			iCombatStr = pUnit.baseCombatStr() + 100 * pUnit.bombardRate() + pUnit.airBaseCombatStr() + 100 * pUnitTypeInfo.getBombRate()
			# retrieve Unit type info
			eUnitType = pUnit.getUnitType()
			# retrieve unit level
			iLevel = pUnit.getLevel()
			# retrieve unit experience
			iXP = pUnit.getExperience()	
			# if unit has cargo...
			if pUnit.cargoSpace() > 0:
				iTransportUnit = pUnit.getID()
			else:
				iTransportUnit = 0
			# in case of promotion view, do not consider combat strngth, unit level and unit experience. Otherise the sorting will change during promotion process
			if (self.nPLEGrpMode == self.PLE_GRP_PROMO):
				# return negatives for some elements for descending sorting of related column.			
				tReturn = (iPlayer, eDomainType, -iGroupID, 0, -eUnitType, 0, 0, iTransportUnit, 0, pUnit.getID(), pUnit)
			else:
				# return negatives for some elements for descending sorting of related column.			
				tReturn = (iPlayer, eDomainType, -iGroupID, -iCombatStr, -eUnitType, -iLevel, -iXP, iTransportUnit, 0, pUnit.getID(), pUnit)
			return tReturn
			
	# creates a sorted unit list of the plot depending on the current grouping
	def getUnitList(self, pPlot):
		# local list to store unit order
		self.lPLEUnitList = []
		# loop for all units on the actual plot
		for i in range(pPlot.getNumUnits()):
			# retrieve single unit
			pUnit = pPlot.getUnit(i)
			# only units which are visible for the player 
			if not pUnit.isInvisible(gc.getPlayer(gc.getGame().getActivePlayer()).getTeam(), true):
				# check if the unit is loaded into any tranporter
				# append empty list element. Each element stores the following information in given order :
				lUnitInfo = self.getPLEUnitInfo(pUnit)
				self.lPLEUnitList.append( lUnitInfo )
				self.dPLEUnitInfo[ pUnit.getID() ] = lUnitInfo
		# sort list
		self.lPLEUnitList.sort()			
		
	# replaces the buggy civ 4 version.
	def getInterfacePlotUnit(self, i):
		return self.lPLEUnitList[i][self.IDX_UNIT]

	# displays all the possible promotion buttons for a unit 
	def displayUnitPromos(self, screen, pUnit, nRow, nCol):
		lPromos = mt.getPossiblePromos(pUnit)
		# remove the 'Lead by Warlord' promotion, if any
		for i in range(len(lPromos)):
			if (gc.getPromotionInfo(lPromos[i]).getType() == 'PROMOTION_LEADER'):
				lPromos.pop(i)
				break
		# determine which dimension is the unit and which the promotion
		if (self.sPLEMode == self.PLE_MODE_STACK_HORIZ):
			iU = nRow
		else:
			iU = nCol
		# display the promotions
		for i in range(len(lPromos)):
			if (self.sPLEMode == self.PLE_MODE_STACK_HORIZ):
				nCol += 1
			else:
				nRow += 1
			x = self.getX( nCol )
			y = self.getY( nRow )
			if (self.sPLEMode == self.PLE_MODE_STACK_HORIZ):
				iP = nCol
			else:
				iP = nRow
			iPromo = lPromos[i]
			sID = string.zfill(str(iU), 2) + string.zfill(str(iP), 2)
			szStringUnitPromo = self.PLOT_LIST_PROMO_NAME + sID
			szFileNamePromo = gc.getPromotionInfo(iPromo).getButton()
			screen.setImageButton( szStringUnitPromo, szFileNamePromo, x, y, 32, 32, WidgetTypes.WIDGET_GENERAL, gc.getPromotionInfo(iPromo).getActionInfoIndex(), -1 )
			screen.show( szStringUnitPromo )
		self.dUnitPromoList[iU] = lPromos
		return

	# performs the units promotion
	def doPromotion(self, id):
		idPromo		= id % 100
		idUnit		= id / 100
		if self.sPLEMode == self.PLE_MODE_STACK_HORIZ:
			idButton = self.getI(idUnit, 0)
		else:
			idButton = self.getI(0, idUnit)
		pUnit 		= self.listPLEButtons[idButton][0]
		iPromo		= self.dUnitPromoList[idUnit][idPromo-1]
		pUnit.promote(iPromo, -1)
		
		
	# displays all the possible upgrade buttons for a unit 
	def displayUnitUpgrades(self, screen, pUnit, nRow, nCol):
		lUpgrades 	= []
		lUnits		= []
		
		# reading all upgrades
		lUpgrades = mt.getPossibleUpgrades(pUnit)
		
		# determine which dimension is the unit and which the upgrade
		if (self.sPLEMode == self.PLE_MODE_STACK_HORIZ):
			iU = nRow
		else:
			iU = nCol
		
		# displaying the results
		for i in range(len(lUpgrades)):
			if (self.sPLEMode == self.PLE_MODE_STACK_HORIZ):
				nCol += 1
			else:
				nRow += 1
			x = self.getX( nCol )
			y = self.getY( nRow )
			if (self.sPLEMode == self.PLE_MODE_STACK_HORIZ):
				iP = nCol
			else:
				iP = nRow
			iUnitIndex = lUpgrades[i]
			lUnits.append(iUnitIndex)
			sID = string.zfill(str(iU), 2) + string.zfill(str(iP), 2)
			szStringUnitUpgrade = self.PLOT_LIST_UPGRADE_NAME + sID
			szFileNameUpgrade = gc.getUnitInfo(iUnitIndex).getButton()
			screen.setImageButton( szStringUnitUpgrade, szFileNameUpgrade, x, y, 34, 34, WidgetTypes.WIDGET_GENERAL, iUnitIndex, -1 )
			if pUnit.canUpgrade(iUnitIndex, false):
				screen.enable(szStringUnitUpgrade, true)
			else:
				screen.enable(szStringUnitUpgrade, false)
			screen.show( szStringUnitUpgrade )
		self.dUnitUpgradeList[iU] = lUnits
		return
			
	# performs the unit upgrades
	def doUpgrade(self, id):
		idUpgrade		= id % 100
		idUnit			= id / 100
		if self.sPLEMode == self.PLE_MODE_STACK_HORIZ:
			idButton = self.getI(idUnit, 0)
		else:
			idButton = self.getI(0, idUnit)
		pUnit 			= self.listPLEButtons[idButton][0]
		iUnitType		= self.dUnitUpgradeList[idUnit][idUpgrade-1]		
		if mt.bCtrl():
			pPlot = pUnit.plot()
			iCompUnitType = pUnit.getUnitType()
			for i in range(pPlot.getNumUnits()):
				pLoopUnit = pPlot.getUnit(i)
				if (pLoopUnit.getUnitType() == iCompUnitType):
					pLoopUnit.doCommand(CommandTypes.COMMAND_UPGRADE, iUnitType, 0)
		elif mt.bAlt():
			pActPlayer = gc.getActivePlayer()
			iCompUnitType = pUnit.getUnitType()
			for i in range(pActPlayer.getNumUnits()):
				pLoopUnit = pActPlayer.getUnit(i)
				if (pLoopUnit.getUnitType() == iCompUnitType):
					pLoopUnit.doCommand(CommandTypes.COMMAND_UPGRADE, iUnitType, 0)
		else:
			pUnit.doCommand(CommandTypes.COMMAND_UPGRADE, iUnitType, 0)		

	##################### info pane (mouse over) functions ########################
		
	# handles display of the promotion button info pane
	def showPromoInfoPane(self, id):
		screen = CyGInterfaceScreen( "MainInterface", CvScreenEnums.MAIN_INTERFACE )
		idPromo		= id % 100
		idUnit		= id / 100
		if self.sPLEMode == self.PLE_MODE_STACK_HORIZ:
			idButton = self.getI(idUnit, 0)
		else:
			idButton = self.getI(0, idUnit)
		pUnit 		= self.listPLEButtons[idButton][0]
		iPromo		= self.dUnitPromoList[idUnit][idPromo-1]
		
		# promo info
		szPromoInfo = u"<font=2>" + mt.removeLinks(CyGameTextMgr().getPromotionHelp(iPromo, false)) + u"</font>\n"
		
		# unit level 
		iLevel = pUnit.getLevel()
		iMaxLevel = mt.GetPossiblePromotions(pUnit.experienceNeeded(), pUnit.getExperience())
		if iMaxLevel <> iLevel:
			# actual / available (= number of possible promotions)
			szLevel = u"<font=2>" + localText.getText("INTERFACE_PANE_LEVEL", ()) + u"%i / %i" % (iLevel, (iMaxLevel+iLevel)) + u"</font>\n"
		else:
			# actual 
			szLevel = u"<font=2>" + localText.getText("INTERFACE_PANE_LEVEL", ()) + u"%i" % iLevel + u"</font>\n"

		# unit experience (actual / needed)
		iExperience = pUnit.getExperience()
		if (iExperience > 0):
			szExperience = u"<font=2>" + localText.getText("INTERFACE_PANE_EXPERIENCE", ()) + u": %i / %i" %(iExperience, pUnit.experienceNeeded()) + u"</font>\n"
		else:
			szExperience = u""
			
		szText = szPromoInfo + szLevel + szExperience
			
		# display the info pane
		self.displayInfoPane(szText)
		
	def hidePromoInfoPane(self):
		self.hideInfoPane()

	# handles display of the promotion button info pane
	def showUpgradeInfoPane(self, id):
		screen = CyGInterfaceScreen( "MainInterface", CvScreenEnums.MAIN_INTERFACE )
		idUpgrade		= id % 100
		idUnit			= id / 100
		if self.sPLEMode == self.PLE_MODE_STACK_HORIZ:
			idButton = self.getI(idUnit, 0)
		else:
			idButton = self.getI(0, idUnit)
		pUnit 			= self.listPLEButtons[idButton][0]
		iUnitType		= self.dUnitUpgradeList[idUnit][idUpgrade-1]		
		pUnitTypeInfo 	= gc.getUnitInfo(iUnitType)		
		
		# reading attributes
		szUnitName 		= localText.changeTextColor(pUnitTypeInfo.getDescription(), PleOpt.getUnitNameColor()) + u"\n"
		if pUnitTypeInfo.getUnitCombatType() != -1:
			szCombatType	= gc.getUnitCombatInfo(pUnitTypeInfo.getUnitCombatType()).getDescription() + u"\n"
		else:
			szCombatType = u""
		if (pUnitTypeInfo.getAirCombat() > 0):
			iStrength = pUnitTypeInfo.getAirCombat()
		else:
			iStrength = pUnitTypeInfo.getCombat()
		szStrength = u"%i "%iStrength + u"%c" % CyGame().getSymbolID( FontSymbols.STRENGTH_CHAR )
		szMovement = u", %i "%pUnitTypeInfo.getMoves()+ u"%c" % CyGame().getSymbolID(FontSymbols.MOVES_CHAR)
		if (pUnitTypeInfo.getAirRange() > 0):
			szRange = u", " + localText.getText("TXT_KEY_UNIT_AIR_RANGE", ( pUnitTypeInfo.getAirRange(), ) ) + u"\n"
		else:
			szRange = u"\n"
		szSpecialText = mt.removeLinks(CyGameTextMgr().getUnitHelp( iUnitType, True, False, False, None )[1:]) + "\n"
			
		# determining the unit upgrade price
		iUpgradePriceSingle 	= mt.getUpgradePrice(pUnit, iUnitType, 0)
	#		iUpgradePriceGrp 		= mt.getUpgradePrice(pUnit, iUnitType, 1)
		iUpgradePricePlot 		= mt.getUpgradePrice(pUnit, iUnitType, 2)
		iUpgradePriceAll 		= mt.getUpgradePrice(pUnit, iUnitType, 3)
		
		iGold = gc.getActivePlayer().getGold()	
		if iUpgradePriceSingle > iGold:
			szUpgradePriceSingle = localText.changeTextColor(u"%i"%iUpgradePriceSingle, PleOpt.getUpgradeNotPossibleColor())
		else:
			szUpgradePriceSingle = localText.changeTextColor(u"%i"%iUpgradePriceSingle, PleOpt.getUpgradePossibleColor())
		if iUpgradePricePlot > iGold:
			szUpgradePricePlot = localText.changeTextColor(u"%i"%iUpgradePricePlot, PleOpt.getUpgradeNotPossibleColor())
		else:
			szUpgradePricePlot = localText.changeTextColor(u"%i"%iUpgradePricePlot, PleOpt.getUpgradePossibleColor())
		if iUpgradePriceAll > iGold:
			szUpgradePriceAll = localText.changeTextColor(u"%i"%iUpgradePriceAll, PleOpt.getUpgradeNotPossibleColor())
		else:
			szUpgradePriceAll = localText.changeTextColor(u"%i"%iUpgradePriceAll, PleOpt.getUpgradePossibleColor())
		
		szUpgradePrice = szUpgradePriceSingle + u" / " + szUpgradePricePlot + u" / " + szUpgradePriceAll+ u" %c" %  gc.getYieldInfo(YieldTypes.YIELD_COMMERCE).getChar() + u"\n"
		
		szUpgradeHelp = localText.getText("TXT_KEY_PLE_UPGRADE_HELP", () )		

		szText 		= u"<font=2>" + szUnitName + \
						szCombatType  + \
						szStrength  + \
						szMovement + \
						szRange  + \
						szSpecialText + \
						szUpgradePrice + \
						szUpgradeHelp + \
					u"</font>"
					
		# display the info pane
		self.displayInfoPane(szText)
				
	def hideUpgradeInfoPane(self):
		self.hideInfoPane()
				
	# handles the display of the unit's info pane
	def showUnitInfoPane(self, id):
		screen = CyGInterfaceScreen( "MainInterface", CvScreenEnums.MAIN_INTERFACE )

		pUnit 			= self.listPLEButtons[id][0]
		iUnitType 		= pUnit.getUnitType()
		pUnitTypeInfo 	= gc.getUnitInfo(iUnitType)
		eUnitDomain 	= pUnitTypeInfo.getDomainType()

		#mt.debug("id:%i; iUnit:%i"%(id, iUnit))
		
		# get units owner name if its not a player unit
		if (pUnit.getOwner() != gc.getGame().getActivePlayer()):
			pOwner = gc.getPlayer(pUnit.getOwner())
			szOwner = u"<font=2> [" + localText.changeTextColor(pOwner.getName(), pOwner.getPlayerColor()) + u"]</font>"
		else:
			szOwner = u""
				
		# unit type description + unit name (if given)
		szUnitName = u"<font=2>" + localText.changeTextColor(pUnit.getName(), PleOpt.getUnitNameColor()) + szOwner + u"</font>\n"
			
		# strength 
		if (eUnitDomain == DomainTypes.DOMAIN_AIR):
			fCurrStrength 	= float(pUnit.airBaseCombatStr() * pUnit.currHitPoints()) / pUnit.maxHitPoints()
			fMaxStrength 	= float(pUnit.airBaseCombatStr())
		else:
			fCurrStrength 	= float(pUnit.baseCombatStr())*float(1.0-pUnit.getDamage()*0.01)
			fMaxStrength 	= float(pUnit.baseCombatStr())
		if fCurrStrength != fMaxStrength:
			if float(fMaxStrength*float(mt.getPlotHealFactor(pUnit))*0.01) == 0:
				iTurnsToHeal = 999
			else:
				iTurnsToHeal 		= int((fMaxStrength-fCurrStrength)/float(fMaxStrength*float(mt.getPlotHealFactor(pUnit))*0.01)+0.999) # force to round upwards
			szCurrStrength 		= u" %.1f" % fCurrStrength
			szMaxStrength 		= u" / %i" % fMaxStrength
			if mt.getPlotHealFactor(pUnit) != 0:
				szTurnsToHeal 		= u" (%i)" % iTurnsToHeal
			else:
				szTurnsToHeal = u" (Not Healing)"
		else: 
			iTurnsToHeal 		= 0
			szCurrStrength 		= u" %i" % fCurrStrength
			szMaxStrength 		= u""		
			szTurnsToHeal 		= u""
		szStrength = u"<font=2>" + szCurrStrength + szMaxStrength + szTurnsToHeal + u"%c" % CyGame().getSymbolID(FontSymbols.STRENGTH_CHAR) + u"</font>\n" 
			
		# movement
		fCurrMoves = float(pUnit.movesLeft()) / gc.getMOVE_DENOMINATOR()
		iMaxMoves = pUnit.baseMoves()
		if (eUnitDomain == DomainTypes.DOMAIN_AIR):
			szAirRange 		= u", " + localText.getText("TXT_KEY_UNIT_AIR_RANGE", ( pUnit.airRange(), ) ) 
		else:
			szAirRange 		= u""
		if ( pUnit.movesLeft() != iMaxMoves * gc.getMOVE_DENOMINATOR() ):
			szCurrMoves = u" %.1f" % fCurrMoves
			szMaxMoves 	= u"/%d" % iMaxMoves
		else:
			szCurrMoves = u" %d" % iMaxMoves
			szMaxMoves 	= u""
		szMovement = u"<font=2>" + szCurrMoves + szMaxMoves + u"%c"%(CyGame().getSymbolID(FontSymbols.MOVES_CHAR)) + szAirRange + u"</font>\n"

		# compressed display for standard display
		szStrengthMovement = u"<font=2>" + szCurrStrength + szMaxStrength + szTurnsToHeal + u"%c" % CyGame().getSymbolID(FontSymbols.STRENGTH_CHAR) + ", " + \
							szCurrMoves + szMaxMoves + u"%c"%(CyGame().getSymbolID(FontSymbols.MOVES_CHAR)) + szAirRange + u"</font>\n"
							
		# civilization type
		szCiv = u""
	#		iCiv = pUnit.getCivilizationType()
	#		for i in range(gc.getMAX_PLAYERS()):
	#			pLoopPlayer = gc.getPlayer(i)
	#			if pLoopPlayer.getCivilizationType() == iCiv:
	#				break
	#		szCiv = u"<font=2>100% " + localText.changeTextColor(pLoopPlayer.getCivilizationAdjective(0), pLoopPlayer.getPlayerColor()) + u"</font>\n"

		# unit level
		iLevel = pUnit.getLevel()
		iMaxLevel = mt.GetPossiblePromotions(pUnit.experienceNeeded(), pUnit.getExperience())
		if (iMaxLevel > 0) or (iLevel > 1):
			if iMaxLevel <> iLevel:
				szLevel = u"<font=2>" + localText.getText("INTERFACE_PANE_LEVEL", ()) + u" %i / %i" % (iLevel, (iMaxLevel+iLevel)) + u"</font>\n"
			else:
				szLevel = u"<font=2>" + localText.getText("INTERFACE_PANE_LEVEL", ()) + u" %i" % iLevel + u"</font>\n"
		else:
			szLevel = u""

		# unit experience (actual / needed (possible promos))
		iExperience = pUnit.getExperience()
		if (iExperience > 0):
			szExperience = u"<font=2>" + localText.getText("INTERFACE_PANE_EXPERIENCE", ()) + u": %i / %i" %(iExperience, pUnit.experienceNeeded()) + u"</font>\n"
		else:
			szExperience = u""

		# cargo space
		iCargoSpace = pUnit.cargoSpace()
		if iCargoSpace > 0:
			iCargo = pUnit.getCargo()
			szCargo = u"<font=2>" + localText.getText("TXT_KEY_UNIT_HELP_CARGO_SPACE", (iCargo, iCargoSpace ) ) + u"</font>\n"
		else:
			szCargo = u""
				
		# fortify bonus
		szFortifyBonus = u"" 
		iFortifyBonus = pUnit.fortifyModifier()
		if iFortifyBonus > 0:
			szFortifyBonus = u"<font=2>" + localText.getText("TXT_KEY_UNIT_HELP_FORTIFY_BONUS", (iFortifyBonus, )) + u"\n" + u"</font>"

		# espionage info; mimic of CvGameTextMgr::setEspionageMissionHelp()
		szEspionage = u""
		if gc.getUnitInfo(pUnit.getUnitType()).isSpy():
			pPlot = pUnit.plot()
			eOwner = pPlot.getOwner()
			pOwner = gc.getPlayer(eOwner)
			if pOwner and not pOwner.isNone():
				eOwnerTeam = pOwner.getTeam()
				if eOwnerTeam != pUnit.getTeam():
					if not pUnit.canEspionage(pPlot):
						szEspionage += localText.getText("TXT_KEY_UNIT_HELP_NO_ESPIONAGE", ())
						if pUnit.hasMoved() or pUnit.isMadeAttack():
							szEspionage += localText.getText("TXT_KEY_UNIT_HELP_NO_ESPIONAGE_REASON_MOVED", ())
						elif not pUnit.isInvisible(eOwnerTeam, False):
							szEspionage += localText.getText("TXT_KEY_UNIT_HELP_NO_ESPIONAGE_REASON_VISIBLE", (pOwner.getNameKey(),))
					elif pUnit.getFortifyTurns() > 0:
						iModifier = - (pUnit.getFortifyTurns() * gc.getDefineINT("ESPIONAGE_EACH_TURN_UNIT_COST_DECREASE"))
						if 0 != iModifier:
							szEspionage += localText.getText("TXT_KEY_ESPIONAGE_COST", (iModifier,))
		if szEspionage:
			szEspionage = u"<font=2>" + szEspionage + u"\n</font>"
		
		# unit type specialities 
		szSpecialText 	= u"<font=2>" + localText.getText("TXT_KEY_PEDIA_SPECIAL_ABILITIES", ()) + u":\n" + CyGameTextMgr().getUnitHelp( iUnitType, true, false, false, None )[1:] + u"</font>"
		szSpecialText = localText.changeTextColor(szSpecialText, PleOpt.getUnitTypeSpecialtiesColor())
		
		if iLevel > 1:
			szSpecialText += "\n" + localText.changeTextColor(mt.getPromotionInfoText(pUnit), PleOpt.getPromotionSpecialtiesColor())
		szSpecialText = mt.removeLinks(szSpecialText)

		# count the promotions
		szPromotion = u""
		iPromotionCount = 0
		for i in range(gc.getNumPromotionInfos()):
			if pUnit.isHasPromotion(i):
				iPromotionCount += 1
		if iPromotionCount > 0:
			szPromotion = u"\n"*((iPromotionCount/self.CFG_INFOPANE_BUTTON_PER_LINE)+1)

		# build text
		szText 	= szUnitName + \
				szPromotion + \
				szStrengthMovement + \
				szLevel + \
				szExperience + \
				szCargo + \
				szCiv + \
				szFortifyBonus + \
				szEspionage + \
				szSpecialText

		# display the info pane
		dy = self.displayInfoPane(szText)
					
		# show promotion buttons
		iTemp = 0
		for i in range(gc.getNumPromotionInfos()):
			if pUnit.isHasPromotion(i):
				szName = self.PLE_PROMO_BUTTONS_UNITINFO + str(i)
				self.displayUnitInfoPromoButtonPos( szName, iTemp, dy - self.CFG_INFOPANE_PIX_PER_LINE_1 + PleOpt.getInfoPanePromoIconOffsetY() )
				screen.show( szName )
				iTemp += 1
							
	def hideUnitInfoPane(self):
		self.hideUnitInfoPromoButtons()
		self.hideInfoPane()
		
	def hideUnitInfoPromoButtons(self):
		screen = CyGInterfaceScreen( "MainInterface", CvScreenEnums.MAIN_INTERFACE )
		for i in range(gc.getNumPromotionInfos()):
			szName = self.PLE_PROMO_BUTTONS_UNITINFO + str(i)
			screen.hide( szName )
		self.bUnitPromoButtonsActive = false

	# displays the unit's promotion buttons in the info pane. They are not part of the info pane.
	def displayUnitInfoPromoButtonPos( self, szName, iPromotionCount, yOffset ):
		self.bUnitPromoButtonsActive = true
		screen = CyGInterfaceScreen( "MainInterface", CvScreenEnums.MAIN_INTERFACE )
		if ( CyInterface().getShowInterface() == InterfaceVisibility.INTERFACE_SHOW ):
			y = self.CFG_INFOPANE_Y
		else:
			y = self.CFG_INFOPANE_Y2
		screen.moveItem( szName, PleOpt.getInfoPaneX() + 4 + (self.CFG_INFOPANE_BUTTON_SIZE * (iPromotionCount % self.CFG_INFOPANE_BUTTON_PER_LINE)), \
								 y + 4 - yOffset + (self.CFG_INFOPANE_BUTTON_SIZE * (iPromotionCount / self.CFG_INFOPANE_BUTTON_PER_LINE)), -0.3 )
		screen.moveToFront( szName )

	# calculates the height of a text in pixels
	def getTextLines(self, szText):
		szText = mt.removeFonts(szText)
		szText = mt.removeColor(szText)
		szText = mt.removeLinks(szText)
		iNormalLines = 0
		iBulletLines = 0
		lChapters = szText.split('\n')
		sComp = u"%c"%CyGame().getSymbolID(FontSymbols.BULLET_CHAR)
		for i in range(len(lChapters)):
			iLen = len(lChapters[i])
			iWidth = CyInterface().determineWidth(lChapters[i])/(self.CFG_INFOPANE_DX-3)+1
			if (lChapters[i].find(sComp) != -1):
				iBulletLines += iWidth
			else:
				iNormalLines += iWidth
		dy = iNormalLines*self.CFG_INFOPANE_PIX_PER_LINE_1 + (iBulletLines)*self.CFG_INFOPANE_PIX_PER_LINE_2 + 20
		return dy
		
	# base function to display a self sizing info pane
	def displayInfoPane(self, szText):

		self.bInfoPaneActive 	= True
		self.iInfoPaneCnt  		+= 1
		self.tLastMousePos 		= (CyInterface().getMousePos().x, CyInterface().getMousePos().y)

		screen = CyGInterfaceScreen( "MainInterface", CvScreenEnums.MAIN_INTERFACE )
		
		# calculate text size
		dy = self.getTextLines(szText)
		
		# draw panel
		if ( CyInterface().getShowInterface() == InterfaceVisibility.INTERFACE_SHOW ):
			y = self.CFG_INFOPANE_Y
		else:
			y = self.CFG_INFOPANE_Y2
		dx = 0
		if ( CyInterface().isCityScreenUp()):
			dx = 260
		
		screen.addPanel( self.UNIT_INFO_PANE, u"", u"", True, True, \
						PleOpt.getInfoPaneX() + dx, y - dy, self.CFG_INFOPANE_DX, dy, \
						PanelStyles.PANEL_STYLE_HUD_HELP )
		
		# create shadow text
		szTextBlack = localText.changeTextColor(mt.removeColor(szText), gc.getInfoTypeForString("COLOR_BLACK"))
		
		# display shadow text
		screen.addMultilineText( self.UNIT_INFO_TEXT_SHADOW, szTextBlack, \
								PleOpt.getInfoPaneX() + dx + 5, y - dy + 5, \
								self.CFG_INFOPANE_DX - 3, dy - 3, \
								WidgetTypes.WIDGET_GENERAL, -1, -1, \
								CvUtil.FONT_LEFT_JUSTIFY)
		# display text
		screen.addMultilineText( self.UNIT_INFO_TEXT, szText, \
								PleOpt.getInfoPaneX() + dx + 4, y - dy + 4, \
								self.CFG_INFOPANE_DX - 3, dy - 3, \
								WidgetTypes.WIDGET_GENERAL, -1, -1, \
								CvUtil.FONT_LEFT_JUSTIFY)
					
		return dy

	def checkInfoPane(self, tMousePos):
		if self.bInfoPaneActive and (self.iInfoPaneCnt == (self.iLastInfoPaneCnt+1)): 
			if (tMousePos.x < self.tLastMousePos[0]-self.iMousePosTol) or \
				(tMousePos.x > self.tLastMousePos[0]+self.iMousePosTol) or \
				(tMousePos.y < self.tLastMousePos[1]-self.iMousePosTol) or \
				(tMousePos.y > self.tLastMousePos[1]+self.iMousePosTol):
				self.hideInfoPane()
				if self.bUnitPromoButtonsActive:
					self.hideUnitInfoPromoButtons()


	#################### functions for a units move area #######################
		
	# highlights the move area
	def highlightMoves(self, id):
		if PleOpt.isShowMoveHighlighter():
			pUnit = self.listPLEButtons[id][0]
			self.ASMA.highlightMoveArea(pUnit)

	# hides the move area
	def dehighlightMoves(self):
		if PleOpt.isShowMoveHighlighter():
			self.ASMA.dehighlightMoveArea()
		

	################## set / get PLE values ##################
	def setPLEUnitList(self, bValue):
		self.bUpdatePLEUnitList = bValue

	def getPLEUnitList(self):
		return self.bUpdatePLEUnitList
