

import time,random
import pygame
from pygame.locals import *


from common import *


class base_Thing(pygame.sprite.Sprite):

  def dump(s,off=''):
    print off,'Thing %s  @%s  t:%s o:%s'%(id(s),s.pos,s.IS_TILE,s.IS_OBJECT)
    print off,'  ',s.blueprints
    print off,'  ',s.image_sources
    print off,'  light:%s',s.light
    s.mydump(off+'MY:')
    if s.IS_TILE:
      for ch in s.contains:
        ch.dump(off+'ch::')
  def mydump(s,off=''):
    pass
  def __repr__(s):
    return '(baseobj@%s %s)'%(s.pos,s.blueprints[0].name)

  def __init__(s,game,pos,blueprints):
    # SDL stuff
    pygame.sprite.Sprite.__init__(s) #call Sprite initializer
    # generic
    s.properties={}  # los block %, move cost, etc
    s.game=game
    s.pos=pos[:]
    s.blueprints=blueprints
    s.redraw=1
    s.events=[]
    s.event_next=None
    s.move_path=[]
    s.move_dest=None
    s.move_rate=0
    # SDL stuff
    s.image_lookup=s.game.images
    s.image_sources=[]
#    s.image=pygame.Surface( [s.game.tilesize(),s.game.tilesize()]).convert_alpha()
    s.rect=pygame.Rect( pos[0]*SIZE_OF_TILE_IN_PIXELS,
                        pos[1]*SIZE_OF_TILE_IN_PIXELS,
                        SIZE_OF_TILE_IN_PIXELS,
                        SIZE_OF_TILE_IN_PIXELS )
    s.image=pygame.Surface( s.game.tilesize ).convert()
    s.BLOCK_LOS=0
    for b in s.blueprints:
      for im in b.images:
        s.image_sources.append(im)
      if b.check('blocklos'): s.BLOCK_LOS=1
#    print s.image_sources
#    raise 'foo'

  def image_regen(s):       # force a setup
    raise 'Image regen can only be done on TILES',s


  def update(s,cmd,*args):

    if   cmd==UPDATE___CHECK_FOR_EVENTS:
      time,=args
      while time>=s.event_next:
        s.event_do()
    elif cmd==UPDATE___DUMP_RECT:
      print 'update.dump:',s.rect
    elif cmd==UPDATE___MY_DIRTY_DRAW:
      if s.IS_OBJECT: raise 'UPDATE: my_dirty_draw on non tile',s
      s.my_dirty_draw(args[0])
    elif cmd==UPDATE___MOVE_EVERYTHING_BY_DELTA:
      dx,dy,pos=args
      s.pos[0] += dx
      s.pos[1] += dy
      s.rect.move_ip( pos )
    elif cmd==UPDATE___LIGHT_LEVELS:
      if not s.IS_TILE: raise 'update: light level on object?'
      rect=args[0]
      s.light_recalc()
      if rect.colliderect(s.rect):
        s.game.SDLGR_dirty_display_tiles.add(s)
    else:
      raise 'baseThing.update: unkneon command',(s,cmd,args)

  brains=None

  def event_do(s):
    print 'inside event_do',s
    time,cmd,args=s.event_remove()
    if   cmd==EVENT_MOVE:
      raise 'MOVE EVENT'
    elif cmd==EVENT_NEED_BRAINS:
      if s.brains is None:
        raise 'baseThing.event_do: need brains, but no brains',(s,time,cmd,args)
      s.brains(time,args)
    else:
      raise 'baseThing.event_do: unknown command',(s,time,cmd,args)

  def event_add(s,time,type,*args):
    newev=( s.game.time+time, type, args )
    s.events.append( newev )
    s.events.sort()
    s.event_next=newev[0]
    s.game.SDLGR_events.add(s)
  def event_remove(s):
    first=s.events[0]
    del s.events[0]
    if s.events:
      s.event_next=s.events[0][0]
    else:
      s.game.SDLGR_events.remove(s)
      s.event_next=None
    return first

  brains=None        # no brains





class Thing_is_tile(base_Thing):
  IS_OBJECT=0
  IS_TILE=1
  def __init__( s,game,pos,tile_blueprints ):
    base_Thing.__init__(s, game, pos, tile_blueprints)
    s.contains=[]        # things that are in this square (also draw order)
                         #  light sources, players, spawns, rubble,
                         #  door
    s.properties={}      # _generated_ from contains
                         # ie tile[s], blueprints[s], static object, properties
    s.next_to_4=[]
    s.next_to_8=[]
    s.light=0            # current light level
    s.light_sources={}   # { source:level }
    s.is_blocked=0
    s.light=s.game.light_level_to_255(s.pos[0])
    s.light=s.game.light_level_to_255(11-s.pos[0])
    # SDL
    s.rect.h=SIZE_OF_TILE_IN_PIXELS
    s.rect.w=SIZE_OF_TILE_IN_PIXELS
    s.image_regen()       # force a setup

  def mydump(s,off=''):
    print off,'lights==',s.light_sources

  def my_dirty_draw(s,surf):
    pygame.draw.rect(surf,(0,0,0),s.rect,0)
    surf.blit(s.image,s.rect)


  def child_add( s,child ):
    if child not in s.contains: s.contains.append(child)
    s.image_regen()
  def child_del( s,child ):
    if child in s.contains: s.contains.remove(child)
    s.image_regen()

  def move(s,impulse):
    raise 'Thing_is_Tile: move: tiles dont move',s

  def light_recalc(s):
    light=0
    for l in s.light_sources.values():
      light=light+l
    s.light=s.game.light_level_to_255( light )
    s.image_regen()

  def image_regen(s):
    s.image.fill( (0,200,0) )
    if s.pos==[1,7]: print 'dumping marine spawn'
    for im in s.image_sources:
#      if s.IS_OBJECT: print "OBJ",s.pos,im
      s.image.blit( im, AT_0_0 )
      if s.pos==[1,7]: print 'dumping marine spawn:im',id(im),im
    for child in s.contains:
      if s.pos==[1,7]: print 'dumping marine spawn:ch=',child
      for im in child.image_sources:
        s.image.blit( im, AT_0_0 )
        if s.pos==[1,7]: print 'dumping marine spawn:ch.im',id(im),im
    s.image.set_alpha(s.light,RLEACCEL)
    s.game.SDLGR_dirty_display_tiles.add(s)





class Thing_is_object(base_Thing):
  IS_OBJECT=1
  IS_TILE=0
  def __init__( s,game,pos,tile,object_blueprints ):
    base_Thing.__init__(s, game, pos, object_blueprints)
    s.tile=tile
    s.light_strength=0    # light level
    s.light_effects={}    # light _EMMITING_ per hex (dx,dy):val
    s.light=250             # current light level
    # SDL
    s.tile.child_add( s )

  def move(s,impulse):
    s.pos[0] += x
    s.pos[1] += y
    s.rect.x= int(s.pos[0]*SIZE_OF_TILE_IN_PIXELS)
    s.rect.y= int(s.pos[1]*SIZE_OF_TILE_IN_PIXELS)
    tile=s.game.map_get_tile(s.pos[0],s.pos[1])
    if s.tile!=tile:
      s.move_tile(s,tile)
  def move_tile(s,newtile):
    print 'object is moving tile',s,s.pos,newtile.pos
    oldtile=s.tile
    s.tile=newtile
    if s.light_strength:
      s.light_set_strength(s.light_strength)   # turn on in new place
    s.light=s.tile.light


  def light_set_strength(s,newstr):
    # turn off old light.
    for tile in s.light_effects.keys():
      del tile.light_sources[ s ]
      s.game.SDLGR_dirty_display_tiles.add(tile)
    # get light area
    s.light_effects=s.game.map.get_light_area(s.tile,newstr)
    # turn on new light.
    for tile,val in s.light_effects.items():
      tile.light_sources[ s ]=val
      s.game.SDLGR_dirty_display_tiles.add(tile)



class OBJECT_door(Thing_is_object):
  def __init__( s,game,pos,tile,blueprints ):
    Thing_is_object.__init__(s,game,pos,tile,blueprints)

class OBJECT_alien_spawn(Thing_is_object):
  def __init__( s,game,pos,tile,blueprints ):
    Thing_is_object.__init__(s,game,pos,tile,blueprints)

class OBJECT_marine_spawn(Thing_is_object):
  def __init__( s,game,pos,tile,blueprints ):
    Thing_is_object.__init__(s,game,pos,tile,blueprints)
    # events
    s.last_spawn=0.0
#    s.event_add( 3.4, EVENT_NEED_BRAINS )
    s.light_set_strength(5)
    s.light=200
    print 'mspawn',s.pos,s.events
  def brains(s,time,args):
    print 'spawn brains: called'
    if len(s.game.SDLGR_marines)<NUM_MARINES:
      print 'spawn brains: trying for marine birth'
      tile=s.tile
#      print 'spawn brains: tile: spos=',s.pos
#      print 'spawn brains: tile: tile=',tile
#      print 'spawn brains: tile: tilepos=',tile.pos
#      print 'spawn brains: tile: nextto4=',tile.next_to_4
      not_blocked=s.game.map_get_tiles_not_blocked(tile.next_to_4)
#      print 'spawn brains: tile not blocked',not_blocked
      if not_blocked:
#        print 'spawn brains: found free tile!',not_blocked
        sq=random.choice(not_blocked)
        obj=s.game.fact_create_objects( sq.pos,sq,['marine_trooper'] )
#        s.game.SDLGR_marines.add(obj)
        print 'spawn brains: marine at',sq.pos,len( s.game.SDLGR_marines )
      else:
        print 'spawn brains: couldnt find free tile'
    s.event_add( 1.0 + random.random()*1., EVENT_NEED_BRAINS )


class OBJECT_marine_trooper(Thing_is_object):
  def __init__( s,game,pos,tile,blueprints ):
    Thing_is_object.__init__(s,game,pos,tile,blueprints)
    # events
#    s.event_add( 3, EVENT_NEED_BRAINS )
  def brains(s,time,args):
  #  print 'spawn brains!',time,s.pos
#    s.move(.02,.05)
    s.event_add( 2+2*random.random(), EVENT_NEED_BRAINS )


class OBJECT_marine_exit(Thing_is_object):
  def __init__( s,game,pos,tile,blueprints ):
    Thing_is_object.__init__(s,game,pos,tile,blueprints)


class OBJECT_rubble1(Thing_is_object):
  def __init__( s,game,pos,blueprints ):
    Thing_is_object.__init__(s,game,pos,tile,blueprints)


