def check_satisfaction(self):
     if self.task and not self.task.task_ended(): return False
     station = self.owner.module.station
     if self.itemtype == 'Actors':
         if self.tasktype == 'Unload':
             loc = lambda: lambda: station.random_location(modules_to_exclude=[self.owner.module])  
         else: 
             loc = lambda: lambda: [None, self.owner.module.filterNode( self.owner.module.node('Inside') ), None]
         for a in station.actors.values():
             if self.subtype=='All' or a.name == self.subtype:
                 self.task = Task(name = 'Move', severity = "HIGH", task_duration = 3600, fetch_location_method = loc(), owner=a)
                 a.my_tasks.add_task(self.task)
     elif self.tasktype == 'Unload':
         found_any = self.owner.module.stowage.search(self.filter)
         if found_any: 
             if self.itemtype=="Clutter":
                 filter_str = self.filter.target_string()
                 self.task = TaskSequence(name = ''.join(['Move ',filter_str]), severity = "MODERATE")
                 self.task.add_task(Task(name = ''.join(['Pick Up ',filter_str]), severity = "MODERATE", timeout = None, task_duration = 30, fetch_location_method=filtering.Searcher(self.filter,self.owner.module).search, owner=clutter.JanitorMon(self.filter.target)))
                 self.task.add_task(Task(name = ''.join(['Put Away ',filter_str]), severity = "MODERATE", timeout = None, task_duration = 30, fetch_location_method = lambda: station.random_location(modules_to_exclude=[self.owner.module]), owner=self))
                 station.tasks.add_task(self.task)
                 return False
             elif self.itemtype == "Equipment":
                 eq = found_any
                 self.task = TaskSequence(name = ''.join(['Move Equipment']), severity = "MODERATE")
                 self.task.station = self.owner.module.station
                 self.task.add_task(Task(name = ''.join(['Pick Up']), owner = eq, timeout=None, task_duration = 60, severity='MODERATE', fetch_location_method=filtering.Searcher(eq,station,check_storage=True).search,station=station))
                 self.task.add_task(Task(name = ''.join(['Put Down']), owner = eq, timeout=None, task_duration = 60, severity='MODERATE', fetch_location_method=lambda: station.random_location(modules_to_exclude=[self.owner.module]),station=station))
                 station.tasks.add_task(self.task)
                 return False
     elif self.tasktype == 'Load':
         found_any = self.owner.module.stowage.search(self.filter)
         if not found_any or (found_any.volume < self.taskamt and self.owner.module.stowage.free_space > 0.25):
             found_any = self.owner.module.station.search(self.filter,modules_to_exclude=[self.owner.module])   
             if found_any[0]:
                 if self.itemtype == "Clutter":
                     filter_str = self.filter.target_string()
                     self.task = TaskSequence(name = ''.join(['Move ',filter_str]), severity = "MODERATE")
                     self.task.add_task(Task(name = ''.join(['Pick Up ',filter_str]), severity = "MODERATE", timeout = None, task_duration = 30, fetch_location_method=filtering.Searcher(self.filter,station,exclude=[self.owner.module]).search, owner=clutter.JanitorMon(self.filter.target)))
                     self.task.add_task(Task(name = ''.join(['Put Away ',filter_str]), severity = "MODERATE", timeout = None, task_duration = 30, fetch_location_method = lambda: [None, self.owner.module.filterNode( self.owner.module.node('Inside') ), None], owner=self))
                     station.tasks.add_task(self.task)
                     return False   
                 elif self.itemtype == "Equipment":
                     eq = found_any[0]
                     self.task = TaskSequence(name = ''.join(['Move Equipment']), severity = "MODERATE")
                     self.task.station = self.owner.module.station
                     self.task.add_task(Task(name = ''.join(['Pick Up']), owner = eq, timeout=None, task_duration = 60, severity='MODERATE', fetch_location_method=filtering.Searcher(eq,station,exclude=[self.owner.module]).search,station=station))
                     self.task.add_task(Task(name = ''.join(['Put Down']), owner = eq, timeout=None, task_duration = 60, severity='MODERATE', fetch_location_method=lambda: [None, self.owner.module.filterNode( self.owner.module.node('Inside') ), None],station=station))
                     station.tasks.add_task(self.task)
                     return False    
                   
     return True
class Storage(Equipment):
    def __init__(self, **kwargs):
        super(Storage, self).__init__(**kwargs)         
        self.stowage = clutter.Stowage(1) #things floating around in the rack
        if not hasattr(self,'filter'): self.filter = ClutterFilter(['All']) 
        self.space_trigger = 0.1 #free volume
        self.type = 'STORAGE'
                    
    def refresh_image(self):     
        super(Storage, self).refresh_image()
        
    def dump_task(self):
        if self.task and self.task.active and self.task.name is "Dump Out": return
        self.task = Task(name = ''.join(['Dump Out']), owner = self, task_duration = 60, fetch_location_method=Searcher(self,self.installed.station).search,station=self.installed.station)
        self.installed.station.tasks.add_task(self.task)    
        
    def update(self,dt):
        #print 'Available storage for ',self.filter.target_string(),': ',self.available_space
        super(Storage, self).update(dt)
        self.stowage.update(dt)        
        #if self.task: print self.task.name
        if self.installed and (not self.task or self.task.task_ended()) and \
                            self.get_available_space() >= self.space_trigger:
            #find stuff to store    
            #sequence! 
            #Task 1: find stuff to store, go to, pick up  #Task 2: find self, go to, deposit
            filter_str = self.filter.target_string()
            self.task = TaskSequence(name = ''.join(['Store ',filter_str]), severity = "LOW",logger=self.logger)
            self.task.add_task(Task(name = ''.join(['Pick Up ',filter_str]), severity = "LOW", timeout = 86400, task_duration = 30, fetch_location_method=Searcher(self.filter,self.installed.station).search, owner=clutter.JanitorMon(self.filter.target),logger=self.logger))
            self.task.add_task(Task(name = ''.join(['Put Away ',filter_str]), severity = "LOW", timeout = 86400, task_duration = 30, fetch_location_method = Searcher( SearchFilter( self ), self.installed.station ).search, owner=self,logger=self.logger))
            self.installed.station.tasks.add_task(self.task)
        
    def get_available_space(self): return self.stowage.free_space       
    available_space = property(get_available_space, None, None, "Available storage space" )    
    
    def task_work_report(self,task,dt):
        
        if task.name.startswith('Put Away'):
            item = task.assigned_to.inventory.search(self.filter)
            if not item: return
            remove_amt = min(clutter.gather_rate*dt*item.density,self.available_space*item.density,item.mass)
            if remove_amt <= 0: return         
            obj = item.split(remove_amt)
            self.stowage.add(obj)                         
            
    def task_finished(self,task):
        super(Storage, self).task_finished(task)         
        if task.name.startswith('Dump Out'):
            for c in self.stowage.contents:
                  self.installed.stowage.add(c)
            self.stowage.contents=[]
        self.update(0)           
 def install_task(self,station):
     if self.installed or not station: return
     self.task = TaskSequence(name = ''.join(['Install Equipment']), severity = "LOW", logger=self.logger)
     self.task.station = station
     self.task.add_task(Task(name = ''.join(['Pick Up']), owner = self, timeout=86400, task_duration = 60, severity='LOW', fetch_location_method=Searcher(self,station,check_storage=True).search,station=station))
     self.task.add_task(Task(name = ''.join(['Install']), owner = self, timeout=86400, task_duration = 600, severity='LOW', fetch_location_method=Searcher(EquipmentFilter(target=self.type, comparison_type="Equipment Slot"),station).search,station=station))
     station.tasks.add_task(self.task)
 def update(self,dt):
     super(Window, self).update(dt)        
     if self.installed and not self.task or self.task.task_ended():
         comms, d, d = self.installed.station.search( EquipmentFilter( target='Comms' ) )
         if comms:
             #stellar observations TODO vary the observables - military spying, geological data, etc
             self.task = TaskSequence(name = ''.join(['Conduct Stellar Observations']), severity = "IGNORABLE", logger=self.logger)            
             self.task.add_task(Task(''.join(['Collect Data']), owner = self, timeout=None, task_duration = 1800, severity='IGNORABLE', fetch_location_method=Searcher(self,self.installed.station).search,logger=self.logger))
             self.task.add_task(Task(''.join(['Report Star Data']), owner = comms, timeout=None, task_duration = 300, severity='IGNORABLE', fetch_location_method=Searcher(comms,self.installed.station).search,logger=self.logger))
             
             self.installed.station.tasks.add_task(self.task)  
class Window(Equipment): #might even be too basic for equipment, but ah well.
    def __init__(self):
        super(Window, self).__init__()       
        self.name = "Window"
        self.in_vaccuum = True
        
    def refresh_image(self):     
        super(Window, self).refresh_image()
        if self.sprite is None: return
        self.sprite.add_layer('Window',util.load_image("images/window.png"))
        self.sprite.layer['Equipment'].visible=False
        
    def update(self,dt):
        super(Window, self).update(dt)        
        if self.installed and not self.task or self.task.task_ended():
            comms, d, d = self.installed.station.search( EquipmentFilter( target='Comms' ) )
            if comms:
                #stellar observations TODO vary the observables - military spying, geological data, etc
                self.task = TaskSequence(name = ''.join(['Conduct Stellar Observations']), severity = "IGNORABLE", logger=self.logger)            
                self.task.add_task(Task(''.join(['Collect Data']), owner = self, timeout=None, task_duration = 1800, severity='IGNORABLE', fetch_location_method=Searcher(self,self.installed.station).search,logger=self.logger))
                self.task.add_task(Task(''.join(['Report Star Data']), owner = comms, timeout=None, task_duration = 300, severity='IGNORABLE', fetch_location_method=Searcher(comms,self.installed.station).search,logger=self.logger))
                
                self.installed.station.tasks.add_task(self.task)  
 def update(self,dt):
     #print 'Available storage for ',self.filter.target_string(),': ',self.available_space
     super(Storage, self).update(dt)
     self.stowage.update(dt)        
     #if self.task: print self.task.name
     if self.installed and (not self.task or self.task.task_ended()) and \
                         self.get_available_space() >= self.space_trigger:
         #find stuff to store    
         #sequence! 
         #Task 1: find stuff to store, go to, pick up  #Task 2: find self, go to, deposit
         filter_str = self.filter.target_string()
         self.task = TaskSequence(name = ''.join(['Store ',filter_str]), severity = "LOW",logger=self.logger)
         self.task.add_task(Task(name = ''.join(['Pick Up ',filter_str]), severity = "LOW", timeout = 86400, task_duration = 30, fetch_location_method=Searcher(self.filter,self.installed.station).search, owner=clutter.JanitorMon(self.filter.target),logger=self.logger))
         self.task.add_task(Task(name = ''.join(['Put Away ',filter_str]), severity = "LOW", timeout = 86400, task_duration = 30, fetch_location_method = Searcher( SearchFilter( self ), self.installed.station ).search, owner=self,logger=self.logger))
         self.installed.station.tasks.add_task(self.task)
 def craft_parts_task(self, reaction):
     if self.status != 'idle': return False
     
     self.status = 'Constructing: '+ reaction['Output'].keys()[0]
     
     self.reaction_goal = reaction
     self.ready_goal = False
     
     #TODO check tech levels
     
     self.task = TaskSequence(name = ''.join(['Build ',reaction['Output'].keys()[0]]), severity = "MODERATE",logger=self.logger)
     for r in self.reaction_goal['Input'].keys():
         self.append_fetch_task(r)
     
     self.task.add_task(Task(name = ''.join(['Craft resource']), severity = "MODERATE", task_duration = self.min_processing_time, fetch_location_method = Searcher( SearchFilter( self ), self.installed.station ).search, owner=self,logger=self.logger))
     
     self.installed.station.tasks.add_task(self.task)
 def build_equipment_task(self, equip):
     
     if not equip or not hasattr(equip,'reaction') or not equip.reaction: return False
     if not self.configuration in equip.reaction['Reactor']: return False
     if self.status != 'idle': return False
     
     self.status = 'Constructing: '+ str(equip).rsplit('.')[-1]
     
     self.equip_goal = equip        
     self.reaction_goal = equip.reaction
     self.ready_goal = False
     #TODO check tech levels
     
     self.task = TaskSequence(name = ''.join(['Build ',str(equip).rsplit('.')[-1]]), severity = "MODERATE",logger=self.logger)
     for r in self.reaction_goal['Input'].keys():
         self.append_fetch_task(r)
     
     self.task.add_task(Task(name = ''.join(['Assemble item']), severity = "MODERATE", task_duration = 3600, fetch_location_method = Searcher( SearchFilter( self ), self.installed.station ).search, owner=self,logger=self.logger))
     
     self.installed.station.tasks.add_task(self.task)              
class ManifestItem(object):
    def __init__(self, owner, itemtype = 'Clutter', subtype = 'Any', tasktype='Unload', taskamt = 'All' ):
        self.task = None
        self.satisfied = False
        self.owner = owner
        self.tasktype=tasktype
        self.taskamt=taskamt
        self.itemtype=itemtype
        self.subtype=subtype
        self.filter = None
        if itemtype=="Clutter":
            self.filter=filtering.ClutterFilter([subtype],check_storage=True)
        elif itemtype == "Equipment":
            self.filter=filtering.EquipmentFilter(target="Misc",subtype=subtype)
            
    def check_satisfaction(self):
        if self.task and not self.task.task_ended(): return False
        station = self.owner.module.station
        if self.itemtype == 'Actors':
            if self.tasktype == 'Unload':
                loc = lambda: lambda: station.random_location(modules_to_exclude=[self.owner.module])  
            else: 
                loc = lambda: lambda: [None, self.owner.module.filterNode( self.owner.module.node('Inside') ), None]
            for a in station.actors.values():
                if self.subtype=='All' or a.name == self.subtype:
                    self.task = Task(name = 'Move', severity = "HIGH", task_duration = 3600, fetch_location_method = loc(), owner=a)
                    a.my_tasks.add_task(self.task)
        elif self.tasktype == 'Unload':
            found_any = self.owner.module.stowage.search(self.filter)
            if found_any: 
                if self.itemtype=="Clutter":
                    filter_str = self.filter.target_string()
                    self.task = TaskSequence(name = ''.join(['Move ',filter_str]), severity = "MODERATE")
                    self.task.add_task(Task(name = ''.join(['Pick Up ',filter_str]), severity = "MODERATE", timeout = None, task_duration = 30, fetch_location_method=filtering.Searcher(self.filter,self.owner.module).search, owner=clutter.JanitorMon(self.filter.target)))
                    self.task.add_task(Task(name = ''.join(['Put Away ',filter_str]), severity = "MODERATE", timeout = None, task_duration = 30, fetch_location_method = lambda: station.random_location(modules_to_exclude=[self.owner.module]), owner=self))
                    station.tasks.add_task(self.task)
                    return False
                elif self.itemtype == "Equipment":
                    eq = found_any
                    self.task = TaskSequence(name = ''.join(['Move Equipment']), severity = "MODERATE")
                    self.task.station = self.owner.module.station
                    self.task.add_task(Task(name = ''.join(['Pick Up']), owner = eq, timeout=None, task_duration = 60, severity='MODERATE', fetch_location_method=filtering.Searcher(eq,station,check_storage=True).search,station=station))
                    self.task.add_task(Task(name = ''.join(['Put Down']), owner = eq, timeout=None, task_duration = 60, severity='MODERATE', fetch_location_method=lambda: station.random_location(modules_to_exclude=[self.owner.module]),station=station))
                    station.tasks.add_task(self.task)
                    return False
        elif self.tasktype == 'Load':
            found_any = self.owner.module.stowage.search(self.filter)
            if not found_any or (found_any.volume < self.taskamt and self.owner.module.stowage.free_space > 0.25):
                found_any = self.owner.module.station.search(self.filter,modules_to_exclude=[self.owner.module])   
                if found_any[0]:
                    if self.itemtype == "Clutter":
                        filter_str = self.filter.target_string()
                        self.task = TaskSequence(name = ''.join(['Move ',filter_str]), severity = "MODERATE")
                        self.task.add_task(Task(name = ''.join(['Pick Up ',filter_str]), severity = "MODERATE", timeout = None, task_duration = 30, fetch_location_method=filtering.Searcher(self.filter,station,exclude=[self.owner.module]).search, owner=clutter.JanitorMon(self.filter.target)))
                        self.task.add_task(Task(name = ''.join(['Put Away ',filter_str]), severity = "MODERATE", timeout = None, task_duration = 30, fetch_location_method = lambda: [None, self.owner.module.filterNode( self.owner.module.node('Inside') ), None], owner=self))
                        station.tasks.add_task(self.task)
                        return False   
                    elif self.itemtype == "Equipment":
                        eq = found_any[0]
                        self.task = TaskSequence(name = ''.join(['Move Equipment']), severity = "MODERATE")
                        self.task.station = self.owner.module.station
                        self.task.add_task(Task(name = ''.join(['Pick Up']), owner = eq, timeout=None, task_duration = 60, severity='MODERATE', fetch_location_method=filtering.Searcher(eq,station,exclude=[self.owner.module]).search,station=station))
                        self.task.add_task(Task(name = ''.join(['Put Down']), owner = eq, timeout=None, task_duration = 60, severity='MODERATE', fetch_location_method=lambda: [None, self.owner.module.filterNode( self.owner.module.node('Inside') ), None],station=station))
                        station.tasks.add_task(self.task)
                        return False    
                      
        return True
                      
    
    def get_some_satisfaction(self):
        self.satisfied = self.check_satisfaction()
        if self.satisfied: return True
        
    def task_work_report(self,task,dt):
        if task.name.startswith('Put Away'):
            item = task.assigned_to.inventory.search(self.filter)
            if not item: return
            remove_amt = min(clutter.gather_rate*dt*item.density,item.mass)
            if remove_amt <= 0: return         
            obj = item.split(remove_amt)
            self.owner.module.station.get_module_from_loc(task.location).stowage.add(obj) 
            
    def task_dropped(self,task):
        if task.name.startswith('Put Away'): #Drop your crap wherever you are
            item = task.assigned_to.inventory.search(self.filter)
            if not item: return
            remove_amt = item.mass
            if remove_amt <= 0: return         
            obj = item.split(remove_amt)
            self.owner.module.station.get_module_from_loc(task.assigned_to.location).stowage.add(obj)                              
            
    def conflicts(self,other): #currently unused
        '''given another manifest item, returns true if the two requirements conflict'''
        if not isinstance(other,ManifestItem): raise TypeError("ManifestItems must only conflict with other ManifestItems")
        if (self.tasktype == 'Unload' and other.tasktype == "Load") or (other.tasktype == 'Unload' and self.tasktype == "Load"):
            if self.itemtype == other.itemtype:
                if self.subtype == other.subtype or self.subtype == "Any" or other.subtype == "Any":
                    return True
        return False 
        
    def cancel(self): #when removed, manifest tasks should be dropped
        if self.task and not self.task.task_ended():
            self.task.drop()
        if self.itemtype == 'Actors':            
            for a in self.owner.module.station.actors.values():
                if self.subtype=='All' or a.name == self.subtype:
                    #task = Task(name = 'Move', severity = "HIGH", task_duration = 3600, fetch_location_method = loc(), owner=a)
                    #a.my_tasks.add_task(task)    
                    a.my_tasks.cancel_task('Move')
class WorkbenchRack(Rack, Workshop):
    configuration = 'Workbench' #space suitable for building small equipment from parts

    def __init__(self):
        
        Workshop.__init__(self) 
        Rack.__init__(self)                    
        
        self.name = "Workbench InnaBox"
        self.local_parts = clutter.Stowage(3)
        self.equip_goal = None
        self.recipe_goal = None
        self.ready_goal = False
        
    def update(self,dt):            
        Workshop.update(self,dt)
        Rack.update(self,dt)       
    
    def generate_dialog_options(self):
        out=[]
        for e in util.equipment_targets.keys():
            eq = util.equipment_targets[e]
            if hasattr(eq,'reaction') and eq.reaction['Reactor'] == self.configuration:
                if hasattr(eq,'fancy_name'):
                    out.append([e,eq.fancy_name])
                else:
                    out.append([e,e])
        return out
                
        
    def build_equipment_task(self, equip):
        
        if not equip or not hasattr(equip,'reaction') or not equip.reaction: return False
        if not self.configuration in equip.reaction['Reactor']: return False
        if self.status != 'idle': return False
        
        self.status = 'Constructing: '+ str(equip).rsplit('.')[-1]
        
        self.equip_goal = equip        
        self.reaction_goal = equip.reaction
        self.ready_goal = False
        #TODO check tech levels
        
        self.task = TaskSequence(name = ''.join(['Build ',str(equip).rsplit('.')[-1]]), severity = "MODERATE",logger=self.logger)
        for r in self.reaction_goal['Input'].keys():
            self.append_fetch_task(r)
        
        self.task.add_task(Task(name = ''.join(['Assemble item']), severity = "MODERATE", task_duration = 3600, fetch_location_method = Searcher( SearchFilter( self ), self.installed.station ).search, owner=self,logger=self.logger))
        
        self.installed.station.tasks.add_task(self.task)              
    
    def task_work_report(self,task,dt):
        Workshop.task_work_report(self,task,dt) 
        if task.name.startswith('Assemble item') and not self.ready_goal:
            for r in self.reaction_goal['Input'].keys():
                filt = ClutterFilter([r])
                vol = self.local_parts.search_info(filt)[1]
                if vol < self.reaction_goal['Input'][r]:
                    self.logger.info("Delaying assembly!  Reason: "+r)
                    task.drop()
                    return
            self.ready_goal = True
            
    def task_finished(self,task):
        Workshop.task_finished(self,task)                         
        if task.name.startswith('Assemble item') and self.ready_goal:
            new_equip = self.equip_goal()
            for r in self.reaction_goal['Input'].keys():
                print r, self.local_parts.contents
                filt = ClutterFilter([r])
                item = self.local_parts.search(filt)
                new_item = item.split(self.reaction_goal['Input'][r] * item.density)
                new_equip.components.append(new_item)
            self.installed.stowage.add(new_equip)
            self.local_parts.dump_into(self.installed.stowage)
            self.status = 'idle'
            if self.repeat: self.build_equipment_task(self.equip_goal)
class MachineShop(Rack, Workshop):
    configuration = 'Machine Shop' #space suitable for building small equipment from parts

    def __init__(self):
        
        Workshop.__init__(self) 
        Rack.__init__(self)                    
        
        self.name = "Machine shop InnaBox"
        self.local_parts = clutter.Stowage(3)
        self.reaction_goal = None
        self.ready_goal = False
        
        self.processing_speed = 0.0001 #m3/s
        self.min_processing_time = util.seconds(15,'minutes')
        self.batch_progress = 0.0
        
    def update(self,dt):            
        Workshop.update(self,dt)
        Rack.update(self,dt)                            
        
                            
    def craft_parts_task(self, reaction):
        if self.status != 'idle': return False
        
        self.status = 'Constructing: '+ reaction['Output'].keys()[0]
        
        self.reaction_goal = reaction
        self.ready_goal = False
        
        #TODO check tech levels
        
        self.task = TaskSequence(name = ''.join(['Build ',reaction['Output'].keys()[0]]), severity = "MODERATE",logger=self.logger)
        for r in self.reaction_goal['Input'].keys():
            self.append_fetch_task(r)
        
        self.task.add_task(Task(name = ''.join(['Craft resource']), severity = "MODERATE", task_duration = self.min_processing_time, fetch_location_method = Searcher( SearchFilter( self ), self.installed.station ).search, owner=self,logger=self.logger))
        
        self.installed.station.tasks.add_task(self.task)

    def task_work_report(self,task,dt):
        Workshop.task_work_report(self,task,dt)         
        #Rack.task_work_report(self,task,dt)
        if task.name.startswith('Craft resource') and not self.ready_goal:
            for r in self.reaction_goal['Input'].keys():
                filt = ClutterFilter([r])
                vol = self.local_parts.search_info(filt)[1]
                if vol < self.reaction_goal['Input'][r]:
                    self.logger.info("Delaying crafting!  Reason: "+r)
                    task.drop()
                    return
            #run reaction
            clutter.run_reaction(self.reaction_goal,self.local_parts,dt*self.processing_speed)
            self.ready_goal = True        

    def task_finished(self,task):
        Workshop.task_finished(self,task)         
        #Rack.task_finished(self,task)
        if task.name.startswith('Craft resource') and self.ready_goal:
            self.local_parts.dump_into(self.installed.stowage)
            self.status = 'idle'
            if self.repeat: self.craft_parts_task(self.reaction_goal)
class Equipment(object):
    def __init__(self, installed=None, logger=None, name='UnspecifiedEquipment'):
        self.installed=None #pointer to module if installed, none if loose
        self.mass=100
        self.task=None
        self.power_usage = 0 #in kilowatts        
        self.powered = False
        self.idle_draw = 0 #in kilowatts
        self.in_vaccuum = False #if True, requires EVA to service        
        self.volume = 1.3 #m^3
        self.broken = False
        self.name = name
        self.type = 'Misc'
        self.satisfies = dict() #what qualities can this equipment provide?
        self.logger = logging.getLogger(logger.name + '.' + self.name) if logger else util.generic_logger
        self.visible = True
        self.sprite=None
        #basic health stats and such go here, as well as hooking into the task system
        
        #if not hasattr(self,'imgfile'): self.imgfile = "images/placeholder_equipment.tif"
        self.refresh_image()    
     
    def refresh_image(self):
        if not util.GRAPHICS == 'pyglet': return        
        import graphics
        if not self.sprite: self.sprite = graphics.LayeredSprite(name=self.name)        
        self.sprite.add_layer('Equipment',util.make_solid_image(40,40,(100,100,100,255)))
               
      
    def update(self,dt):
        if self.task and self.task.task_ended(): self.task = None        
        
        self.powered = self.idle_draw and self.draw_power(self.idle_draw,dt) > 0

    def install(self,home,loc=None):
        if self.installed: return None # "Can't install the same thing twice!"
        self.installed=home
        if loc: self.installed.equipment[loc][3] = self
        if self.installed.station: self.logger = logging.getLogger(self.installed.station.logger.name +'.' + self.installed.short_id+ '.' + self.name)
        self.logger.debug(''.join([self.name," installed in ",self.installed.id,' at ',str(loc)]))
        return self    
        
    def refresh_station(self):
        if self.installed and self.installed.station:
            self.logger = logging.getLogger(self.installed.station.logger.name +'.' + self.installed.short_id+ '.' + self.name)             
        elif self.station:
            self.logger = logging.getLogger(self.station.logger.name +'.' + self.name)

    def uninstall(self):
        if not self.installed: return None # "Can't install the same thing twice!"
        worked = self.installed.uninstall_equipment(self)
        self.installed=None
        return worked
        
    def draw_power(self,kilowattage,dt): #kilowatts in per seconds
        if self.installed and (not hasattr(self,'broken') or not self.broken): #it's installed, not broken or can't break          
            #self.installed.station.resources.resources['Electricity'].available -= kilowattage*dt/3600            
            #TODO add equivalent heat into module
            return self.installed.station.resources.resources['Electricity'].draw(kilowattage*dt/3600)
        return 0
        
    def task_finished(self,task):
        if task:
            if task.name == "Install" and not self.installed:
                if task.assigned_to.held == self:
                    task.assigned_to.held = None
                else:
                    print "Object not held!"
                self.installed = task.station.get_module_from_loc(task.location)
                self.installed.equipment[task.location.split('|')[1]][3] = self      
            elif task.name == 'Pick Up':
                
                if self.installed: 
                    assert self.uninstall(), 'Unknown error after uninstallation'             
                #print task.location   
                module = task.station.get_module_from_loc(task.location)
                #print module.stowage.contents
                assert module.stowage.remove(self), 'Equipment not found in targeted module'
                task.assigned_to.held=self

    def task_failed(self,task):
        pass     
        
    def install_task(self,station):
        if self.installed or not station: return
        self.task = TaskSequence(name = ''.join(['Install Equipment']), severity = "LOW", logger=self.logger)
        self.task.station = station
        self.task.add_task(Task(name = ''.join(['Pick Up']), owner = self, timeout=86400, task_duration = 60, severity='LOW', fetch_location_method=Searcher(self,station,check_storage=True).search,station=station))
        self.task.add_task(Task(name = ''.join(['Install']), owner = self, timeout=86400, task_duration = 600, severity='LOW', fetch_location_method=Searcher(EquipmentFilter(target=self.type, comparison_type="Equipment Slot"),station).search,station=station))
        station.tasks.add_task(self.task)
 def dump_task(self):
     if self.task and self.task.active and self.task.name is "Dump Out": return
     self.task = Task(name = ''.join(['Dump Out']), owner = self, task_duration = 60, fetch_location_method=Searcher(self,self.installed.station).search,station=self.installed.station)
     self.installed.station.tasks.add_task(self.task)