from random import randint
from Numeric import *
from twisted.spread import pb

import common
from game import game
from field import Field, Grunt, Castle

class Map(pb.Copyable, pb.RemoteCopy):
	game_options = ()

	def __init__(self):
		self.castles = []
		self.houses = 0
		self.array = zeros(common.field_size) + Field.EMPTY
		self.build_phase_text = (
			"Repair your walls!",
			"Enclose at least one castle to survive.",
			"Place block / Rotate Block"
		)
		self.place_phase_text = (
			"Place your cannons!",
			"Position new cannons inside your walls.",
			"Place cannon / Select cannon"
		)
		self.battle_phase_text = (
			"Shoot at your enemey's walls!",
			"You can also destroy the cannons.",
			"Shoot / Accelerate movement"
		)
		self.select_phase_text = (
			"Select your Castle!",
			"Choose one castle to be your home castle.",
			"Select Castle / No Action"
		)

	
	def apply(self):
		if 'land_owners' in self.game_options:
			self.set_land_owners()

		game.field.array = self.array
		game.field.add_houses(self.houses)
		self.add_end_test()

		#from field import Castle
		#for castle in self.castles:
		#	Castle(castle['pos'], castle['player'])

		if hasattr(self, 'background_image'):
			game.field.surface = common.load_image(self.background_image)
		else:
			game.field.create_background()

	def set_land_owners(self):
		game.field.owner = where(self.array == Field.RIVER, -1, -2)
		for player in game.players:
			castle = [castle for castle in self.castles if castle.player is player][0]
			common.flood_fill(game.field.owner, castle.pos, -2, player.player_id)
	
	def add_end_test(self):
		def standard_end_test():
			alive = filter(lambda player: player.alive, game.players)
			print "end test %d" % len(alive)
			if len(alive) > 1:			
				return
			if len(alive) == 0:
				string = "Draw game!"
			else:
				string = "%s wins!" % alive[0].name
			print "game end"
			
			from widget import Button, WidgetState
			class EndState(WidgetState):
				def __init__(self):
					WidgetState.__init__(self)
					Button(string, (None, None), None)
					Button("OK", (None, common.screen.get_height()/2 + 50), self.quit)

				def quit(self):
					WidgetState.quit(self)
					game.game_state.quit()
					from state import IgnoreEvent
					raise IgnoreEvent
					
			EndState()
		
		game.build_phase_finished.connect(standard_end_test)

	def getStateToCopy(self):
		state = self.__dict__.copy()
		state['array'] = state['array'].tolist()
		return state
	
	def setCopyableState(self, state):
		state['array'] = array(state['array'])
		self.__dict__ = state


##### Custom Maps #####
		
class GruntAssault(Map):

	title = 'Grunt Assault'
	allowed_players = (1,)

	def __init__(self):
		Map.__init__(self)
		self.houses = 100
		self.castles = [
			Castle(pos=(3 + randint(0, 7) + i * 11, randint(3, 25)), player=None, map=self)
			for i in (0,1,2)
		]
		self.reinforcement_grunts_left = 150;
		def send_reinforcements():
			new_grunts = self.reinforcement_grunts_left / 10;
			self.reinforcement_grunts_left -= new_grunts
			self.add_grunts(new_grunts)
		game.build_phase_finished.connect(send_reinforcements, priority=-10)
		self.battle_phase_text = (
			"Eleminate all attackers!",
			"",
			"Shoot / Accelerate movement"
		)
	
	def apply(self):
		Map.apply(self)
		self.add_grunts(10)

	def add_end_test(self):
		def win_test():
			from widget import Button, WidgetState
			class EndState(WidgetState):
				def __init__(self):
					WidgetState.__init__(self)
					Button('Castle successfully defended!', (None, None), None)
					Button("OK", (None, common.screen.get_height()/2 + 50), self.quit)

				def quit(self):
					WidgetState.quit(self)
					game.game_state.quit()
					from state import IgnoreEvent
					raise IgnoreEvent

			from field import Grunt
			if not Grunt.instances:
				EndState()
	
		def lost_test():
			from widget import Button, WidgetState
			class EndState(WidgetState):
				def __init__(self):
					WidgetState.__init__(self)
					Button('Your last castle has fallen!', (None, None), None)
					Button("OK", (None, common.screen.get_height()/2 + 50), self.quit)

				def quit(self):
					WidgetState.quit(self)
					game.game_state.quit()
					from state import IgnoreEvent
					raise IgnoreEvent

			if not game.players[0].alive:
				EndState()

		game.battle_phase_finished.connect(win_test)
		game.build_phase_finished.connect(win_test)
		game.build_phase_finished.connect(lost_test)
	
	def add_grunts(self, amount):
		player = game.players[0]
		while amount > 0:
			pos = [randint(0, max-1) for max in common.field_size]
			if game.field[pos] == Field.EMPTY and not player.secured[pos]:
				Grunt(pos)
				amount -= 1
			else:
				amount -= 0.1


class RiverMap(Map):

	title = 'River'
	game_options = ('land_owners', )

	def __init__(self):
		Map.__init__(self)
		self.houses = 20


class RiverMap2p(RiverMap):

	allowed_players = (2, )

	def __init__(self):
		RiverMap.__init__(self)
		for y in range(common.field_size[1]):
			self.array[(common.field_size[0]/2 - 1):(common.field_size[0]/2 + 1), y] = Field.RIVER

		for i in (0, 1, 2):
			self.castles += [
				Castle(pos=(8 + randint(-2,2), (i+1) * 8 - 2 + randint(-1,1)), player=game.players[0], map=self),
				Castle(pos=(30 + randint(-2,2), (i+1) * 8 - 2 + randint(-1,1)), player=game.players[1], map=self),
			]

		self.background_image = 'back.jpg'

class RiverMap4p(RiverMap):

	allowed_players = (3, 4)
	
	def __init__(self):
		RiverMap.__init__(self)

		for y in range(common.field_size[1]):
			self.array[(common.field_size[0]/2 - 1):(common.field_size[0]/2 + 1), y] = Field.RIVER
		for x in range(common.field_size[0]):
			self.array[x, (common.field_size[1]/2 - 1):(common.field_size[1]/2 + 1)] = Field.RIVER
		for i in (0, 1):
			self.castles += Castle((5 + randint(-1,1) + i*8, 6 + randint(-1,1)), player=0, map=self)
			self.castles += Castle((25 + randint(-1,1) + i*8, 6 + randint(-1,1)), player=1, map=self)
			self.castles += Castle((5 + randint(-1,1) + i*8, 21 + randint(-1,1)), player=2, map=self)
			if (game.number_of_players == 4):
				self.castles += Castle((25 + randint(-1,1) + i*8, 21 + randint(-1,1)), player=3, map=self)


class ConquerMap(Map):

	title = 'Conquer'
	game_options = ('build_only_near_walls', )
	allowed_players = (2, 3, 4)

	def __init__(self):
		Map.__init__(self)
		self.houses = 20

		def place_castle():
			def is_place_suitable(pos):
				# would the walls be inside the field?
				for i in (0,1):
					if pos[i] not in range(3, common.field_size[i]-4):
						return False

				# enough free room?
				#topleft = common.in_bounds(subtract(pos, 3))
				#bottomright = common.in_bounds(add(pos, 5))
				#surroundings = self.array[topleft[0]:bottomright[0], topleft[1]:bottomright[1]]
				#if sometrue(surroundings != Field.EMPTY):
				#	return False

				# far enough away from other castles
				topleft = common.in_bounds(subtract(pos, 6))
				bottomright = common.in_bounds(add(pos, 8))
				surroundings = self.array[topleft[0]:bottomright[0], topleft[1]:bottomright[1]]
				if sometrue(surroundings == Field.CASTLE):
					return False
				else:
					return True

			while True:
				pos = [randint(0,common.field_size[i]) for i in (0,1)]
				if is_place_suitable(pos):
					self.castles += [ Castle(pos=pos, player=None, map=self), ]
					return

		for i in range(5):
			place_castle()


#	def apply(self):
#		Map.apply(self)


##### Map List #####

maps = (GruntAssault, RiverMap2p, RiverMap4p, ConquerMap)

# does not work. I don't know why.
#import sys
#from twisted.spread.jelly import setUnjellyableForClassTree
#setUnjellyableForClassTree(module=sys.modules[__name__], baseClass=Map, prefix="")

for m in maps:
	pb.setUnjellyableForClass(m, m)

