
import pygame, math, bisect
import gfx, gui, ticker, sheep, playgame, dialog, sheperd, playmode

images = ['question', 'camp_tile', 'ranch_tile', 'village_tile', 'town_tile',
    	  'camp_icon', 'ranch_icon', 'village_icon', 'town_icon',
	  'timer_empty', 'timer_full', 'hammer', 'destroy_icon',
	  
	  'house_tile', 'butcher_tile', 'shearer_tile', 'house2_tile',
	  'craftsman_tile', 'kennel_tile', 'well_tile',
	  'farm_tile', 'doctor_tile', 'church_tile',
	  
	  'play_icon', 'stop_icon',
	 ]
sounds = ['bark', 'butcher', 'sawwood', 'scissors', 'tapglass', 'money', 'static']


class TimedTask:
    def __init__(self, tick, icon, priority, callback, *args):
    	self.ticker = tick
	self.callback = callback
	self.args = args
	self.icon = icon
	self.priority = priority
	self.image1 = images.timer_empty
	self.image2 = images.timer_full
	self.finishing = 0
	self.size = 0
	self.sizeticker = ticker.Ticker(500, 0, 30, ticker.smooth)
	self.percent = 0.0
	
	self.iconrect = gfx.position(icon, midleft=(0,15))
	self.barrect = gfx.position(self.image1, midleft=(25, 15))

    def __cmp__(self, other):
    	return cmp(self.priority, other.priority)
    
    def update(self, time):
    	if self.sizeticker:
    	    self.size = min(self.sizeticker.tick(time), 30)
	elif self.ticker:
    	    self.ticker.tick(time)
	    self.percent = self.ticker.percent
	elif not self.finishing:
	    self.sizeticker = ticker.Ticker(500, 30, 0, ticker.smooth)
	    self.finishing = 1
	    self.callback(*self.args)

    def draw(self, screen, offset):
    	w,h = self.iconrect.size
	h = min(self.size, h)
    	screen.blit(self.icon, self.iconrect.move(offset), (0,0,w,h))
	w,h = self.image1.get_rect().size
	h = min(self.size, h)
	cut = self.ticker.percent * w
	movedbar = self.barrect.move(offset)
	screen.blit(self.image2, movedbar, (0,0,cut,h))
	screen.blit(self.image1, movedbar.move((cut,0)), (cut,0,w,h))
	
thevillage = None	

class Village:
    def __init__(self, pos):
    	global thevillage
	thevillage = self
	
	self.buildings = []
	self.sheep = []
	self.sheperds = []
	self.selectsheperd = None
	self.rect = pygame.Rect(0, 0, 300, 260)
	self.rect.center = pos
	self.pos = pos
	self.corral = Building(images.camp_tile, pos)
	self.townsize = 0
    	self.gold = 14
	
    	self.town_gold = 12, 20, 28, 0
    	self.town_time = 25000, 35000, 45000, 0
    	self.town_limits = 20, 40, 60, 80
	self.town_names = 'Campsite', 'Ranch', 'Village', 'Town'
	self.town_tiles = (images.camp_tile, images.ranch_tile,
	    	    	       images.village_tile, images.town_tile)
    	self.town_icons = (images.camp_icon, images.ranch_icon,
	    	    	   images.village_icon, images.town_icon)

    	self.tasks = []
    	self.birthtime = 0.0

    	self.numwells = 0
	self.wool = 0.0



    def new_building_pos(self):
    	dist = 120
	angle = -15 - len(self.buildings)/5.5 * 360 * (math.pi/180)
	offx = int(math.sin(angle)*dist)
	offy = int(math.cos(angle)*dist)
	pos = self.pos[0]+offx, self.pos[1]+offy
	return pos

    def add_building(self, type):
    	if len(self.buildings) >= 12: return
    	pos = self.new_building_pos()
    	building = type(pos)
	self.buildings.append(building)
	return building
	
    def draw(self, screen, offset):
    	if not gfx.res.colliderect(self.rect.move(offset)): return
	
	self.corral.draw(screen, offset)
	for b in self.buildings:
	    b.draw(screen, offset)
	
	#draw sheep
    	positions = {}
	for s in self.sheperds:
	    x = offset[0] + s.pos[0]
	    y = offset[1] + s.pos[1]
	    positions[s] = x, y
	positions[None] = offset[0]+self.pos[0], offset[1]+self.pos[1]
	for s in self.sheep:
	    x1,y1 = positions[s.sheperd]
	    screen.blit(s.image, (x1+s.posx, y1+s.posy))

    	#draw sheperds
    	for s in self.sheperds:
	    s.draw(screen, offset)

    def changegold(self, change):
    	self.gold = max(self.gold+change, 0)

    def update(self, time):
    	#verify selection
	if not self.selectsheperd and len(self.sheperds):
	    self.selectsheperd = self.sheperds[0]
	elif not len(self.sheperds) and self.selectsheperd:
	    self.selectsheperd = None

    	for b in self.buildings:
	    b.update(time)

    	#sheep
    	for s in self.sheep[:]:
	    if self.numwells:
	    	if not s.sheperd:
	    	    s.water += .001*self.numwells*time
	    s.update(time)
	    if s.dead > 1000:
	    	self.sheep.remove(s)
	    else:
	    	if not s.sheperd:
		    self.birthtime += time*.0001
		else:
		    s.sheperd.birthtime += time*.0001
		    
	#handle birthing
	if len(self.sheep) < self.town_limits[self.townsize]:
	    if self.birthtime > 11.0:
		self.birthtime -= 11.0
		self.sheep.append(sheep.Sheep())
		sheep.sound()
	else:
	    self.birthtime = min(self.birthtime, 15.0)
	
	for s in self.sheperds:
	    s.update(time)
	
	#tasks
	x = 0
	for t in self.tasks[:]:
	    t.update(time)
	    if t.finishing and not t.sizeticker and x<len(self.tasks):
	    	del self.tasks[x]
	    x += 1
    	
    def upgrade_town(self):
    	self.townsize += 1
	self.corral.image = self.town_tiles[self.townsize]
	sounds.tapglass.play()

    def addtask(self, task):
    	bisect.insort(self.tasks, task)



class Building:
    def __init__(self, image, pos):
    	self.pos = pos
	self.image = image
	self.rect = gfx.position(self.image, center=pos)

    def draw(self, screen, offset):
    	screen.blit(self.image, self.rect.move(offset))


class RealBuilding(Building):
    def __init__(self, pos):
    	img = getattr(images, self.image_tile)
	Building.__init__(self, img, pos)
	self.disabled = 1
	self.imagedisabled = gfx.ghost(self.image)
	self.village = playgame.thegame.village #argh!
	self.init()
	self.ticker = None
	self.taskticker = None
    
    def init(self): pass
	
    def draw(self, screen, offset):
    	if self.disabled: img = self.imagedisabled
	else: img = self.image
    	screen.blit(img, self.rect.move(offset))

    def finished_construction(self):
    	self.disabled = 0
	sounds.sawwood.play()

    def pressed(self):
    	if self.disabled: return
	name = self.__class__.__name__
	buttons = self.get_buttons()
	gold = max(int(self.cost_gold * .7), 1)
	time = max(int(self.cost_time * .5), 1000)
	desc =  "You can destroy buildings to reclaim part of the costs. "\
		"You also free a valuable building location."
	b = gui.BuildingButton(self, images.destroy_icon, "Destroy Building", -gold, time,
	    	desc, self.startdestroy, self.finaldestroy)
	
	buttons.insert(0, b)
	img = getattr(images, self.image_tile)
    	dialog.SimpleDialog(name, img, self.description, buttons)
	self.dialog = dialog

    def get_buttons(self):
    	return []

    def startdestroy(self):
	self.disabled = 1 
	sounds.static.play()   	

    def finaldestroy(self):
    	self.village.buildings.remove(self)

    def update(self, time):
    	pass


class House(RealBuilding):
    description = "A sheperd and his family live in these homes."
    cost_gold = 5
    cost_time = 15000
    image_tile = 'house_tile'
    def init(self):
    	self.upgraded = 0
	self.flagimg = None

    def draw(self, screen, offset):
    	if self.disabled: img = self.imagedisabled
	else: img = self.image
	r = self.rect.move(offset)
    	screen.blit(img, r)
	if self.flagimg:
	    screen.blit(self.flagimg, r.move(8	,-2))

    def finished_construction(self):
    	RealBuilding.finished_construction(self)
	shep = sheperd.Sheperd(self)
	self.village.sheperds.append(shep)
	self.flagimg = shep.img.flag

    def get_buttons(self):
    	if self.upgraded: return []
	
	desc = "Upgrade the House to allow the sheperd to rest to full strength quicker."
	b = gui.BuildingButton(self, images.house2_tile, "Upgrade House", 4, 8000, desc,
	    	self.upgradeit, self.upgradedone)
	
    	return [b]

    def upgradeit(self):
	self.disabled = 1    	
    	center = self.rect.center
	self.image = images.house2_tile
	self.imagedisabled = gfx.ghost(images.house2_tile)
	self.rect = gfx.position(self.image, center=center)
	
    def upgradedone(self):
	self.disabled = 0    	
	self.upgraded = 1

    def finaldestroy(self):
    	RealBuilding.finaldestroy(self)
	for s in self.village.sheperds:
	    if s.house is self:
	    	s.house = None
		self.village.sheperds.remove(s)
		for sheep in self.village.sheep[:]:
		    if sheep.sheperd is s:
		    	self.village.sheep.remove(sheep)
	    	break

	

class Butcher(RealBuilding):
    description = "Makes money from sheep by turning them into food."
    cost_gold = 6
    cost_time = 18000
    image_tile = 'butcher_tile'
    def init(self):
    	self.working = 1

    def get_buttons(self):
    	if self.working:	
	    desc = "Stop the butcher working, which will allow more sheep to live."
	    b = gui.BuildingButtonSimple(self, images.stop_icon, "Stop", desc,
	    	    self.stopwork)
	else:
	    desc = "Start the butcher working, which will cost sheep."
	    b = gui.BuildingButtonSimple(self, images.play_icon, "Start", desc,
	    	    self.startwork)
    	return [b]

    def stopwork(self):
    	self.working = 0
    
    def startwork(self):
    	self.working = 1

    def update(self, time):
    	if self.disabled: return
    	if self.ticker:
	    self.ticker.tick(time)
	elif self.working:
	    wool = 100.0 #find with least wool
	    sheep = None
	    for s in self.village.sheep:
	    	if s.sheperd or s.dead: continue
		if s.wool < wool:
		    sheep = s
		    wool = s.wool
	    if sheep:
	    	sheep.dead = 1
		sheep.food = sheep.water = 100.0 #force white icon
	    	#print 'CHOPPING SHEEP'
		sounds.butcher.play()
		self.village.changegold(5)
	    	self.ticker = ticker.Ticker(15000)



class Shearer(RealBuilding):
    description = "Cuts the wool off of sheep and sells it for money."
    cost_gold = 6
    cost_time = 19000
    image_tile = 'shearer_tile'
    def init(self):
    	self.ticker = None
    
    def update(self, time):
    	if self.disabled: return
    	if self.ticker:
	    self.ticker.tick(time)
	else:
	    wool = 35.0 #find with most wool
	    sheep = None
	    for s in self.village.sheep:
	    	if s.sheperd or s.dead: continue
		if s.wool > wool:
		    sheep = s
		    wool = s.wool
	    if sheep:
	    	#print 'SHAVING SHEEP', sheep.wool
		sounds.scissors.play()
	    	self.village.wool += sheep.wool
		sheep.wool = 0.0
		self.village.changegold(self.village.wool / 55.0)
		self.village.wool %= 55.0
	    	self.ticker = ticker.Ticker(8000)




class Craftsman(RealBuilding):
    description = "Creates better equipment for the sheperds. Crafts"\
    	    	  "give many bonuses to the sheep with the sheperd."
    cost_gold = 3
    cost_time = 10000
    image_tile = 'craftsman_tile'

    def init(self):
    	self.busy = 0

    def get_buttons(self):
    	self.sheperd = self.village.selectsheperd
	desc = "Create a tool for the selected sheperd. A crafty sheperd makes happy sheep."
	img = sheperd.images.stick
	if self.sheperd:
	    img = self.sheperd.img.stick
	b = gui.BuildingButton(self, img, "Create Craft", 3, 8000, desc,
	    	self.startcraft, self.craftdone)
	if self.busy or not self.sheperd:
	    b.goldneeded = 10000 #disable
   	return [b]

    def startcraft(self):
    	self.busy = 1

    def craftdone(self):
    	self.busy = 0
	self.sheperd.numcrafts += 1



class Kennel(RealBuilding):
    description = "Breed dogs to travel with the sheperd. Each"\
    	    	  "dog allows a sheperd to take one extra sheep."
    cost_gold = 4
    cost_time = 10000
    image_tile = 'kennel_tile'

    def get_buttons(self):
    	self.sheperd = self.village.selectsheperd
	desc = "Breed a dog for the selected Sheperd. You can breed multiple dogs at "\
	       "the same time."
	img = sheperd.images.dog
	if self.sheperd:
	    img = self.sheperd.img.dog
	b = gui.BuildingButton(self, img, "Breed Dog", 4, 10000, desc,
	    	None, self.dogdone)
	if not self.sheperd:
	    b.goldneeded = 10000 #disable
   	return [b]

    def dogdone(self):
	self.sheperd.numdogs += 1
	sounds.bark.play()


class Well(RealBuilding):
    description = "More water to quickly restore thirsty sheep."
    cost_gold = 3
    cost_time = 18000
    image_tile = 'well_tile'

    def finished_construction(self):
    	RealBuilding.finished_construction(self)
	self.village.numwells += 1

    def finaldestroy(self):
    	RealBuilding.finaldestroy(self)
	self.village.numwells -= 1



class Farm(RealBuilding):
    description = "Allows the fields to grow quicker.\n* unimplemented *"
    cost_gold = 8
    cost_time = 25000
    image_tile = 'farm_tile'

class Vetrinarian(RealBuilding):
    description = "Keeps sheep in the village healthier.\n* unimplemented *"
    cost_gold = 9
    cost_time = 20000
    image_tile = 'doctor_tile'

class Church(RealBuilding):
    description = "Sells sheep to be used in rituals for money.\n* unimplemented *"
    cost_gold = 7
    cost_time = 25000
    image_tile = 'church_tile'
	

building_map = [[House, Butcher, Shearer],
    	     [Craftsman, Kennel, Well],
	     [Farm, Vetrinarian, Church]]






class BuildDialog:
    def __init__(self, vlg):
    	self.village = vlg
	numrows = self.village.townsize
	width = 300
	height = numrows * 60 + 110
	self.backc = 30, 30, 50
	self.forec = 200, 180, 30
    	colorkey = 255, 0, 255
	
	self.image = pygame.Surface((width, height))
	self.image.fill(self.backc)
	self.rect = self.image.get_rect()
	gui.fill_corners(self.image, colorkey, self.rect)
	
	r = self.rect.inflate(-10, -10)
	r.height = 50
	gui.draw_titlebar(self.image, self.forec, self.backc, r, "Construct A Building", images.hammer)

	self.numrows = numrows
	self.rect.center = gfx.res.center

    	#add buttons
	posy = 50
	self.ui_all = []
	for row in building_map[:numrows+1]:
	    posx = self.rect.centerx - len(row)*91
	    for building in row:
	    	name = building.__name__
		img = getattr(images, building.image_tile)
		img = pygame.transform.scale(img, (30, 30))
		icons = gui.render_gold(building.cost_gold), gui.get_clock(building.cost_time)
		tip = gui.render_tooltip(name, icons, building.description, self.backc, self.forec)
		pos = pygame.Rect(posx, posy, 60, 40)
		pos.move_ip(self.rect.topleft)
		btn = gui.Button(img, pos, tip, self.forec, self.buttonpush, building)
		btn.building = building
		self.ui_all.append(btn)
	    	posx += 72
	    posy += 60
	self.ui_all.reverse() #help drawing underneath tooltip
	
	
	self.image.set_colorkey(colorkey)
	self.image = gfx.optimize(self.image)
	playgame.thegame.popup = self
    	


    def draw(self, screen):
    	screen.blit(self.image, self.rect)
    	for b in self.ui_all:
	    b.draw(screen)	    
	
	
    def update(self, time):
    	for b in self.ui_all:
	    b.disabled = self.village.gold < b.building.cost_gold

    def mousemoved(self, pos):
    	for ui in self.ui_all:
	    ui.mousemoved(pos)
    
    def mousepushed(self, pos):
	for ui in self.ui_all:
	    ui.mousepushed(pos)
	return self.rect.collidepoint(pos)
    
    def mousereleased(self, pos):
	for ui in self.ui_all:
	   ui.mousereleased(pos)
	return self.rect.collidepoint(pos)
    
    def buttonpush(self, buildingtype):
	b = self.village.add_building(buildingtype)
	tick = ticker.Ticker(buildingtype.cost_time)
	img = getattr(images, buildingtype.image_tile)
	img = pygame.transform.scale(img, (20,20))
	task = TimedTask(tick, img, 3, b.finished_construction)
	self.village.addtask(task)
	self.village.changegold(-buildingtype.cost_gold)
	self.close()
	
    def close(self):
    	playgame.thegame.popup = None




