class Machinery(Equipment): #ancestor class for things that need regular maintenance
    def __init__(self):
        if not hasattr(self,'imgfile'): self.imgfile = "images/placeholder_machinery.tif"
        super(Machinery, self).__init__()              
        self.idle_draw = 0.001 #kW
        self.maint_timer = random.randrange(util.seconds(6,'months'), util.seconds(2,'years') )
        self.maint_task = None
        self.wear = 1.0
        self.broken = False
            
    def refresh_image(self):     
        super(Machinery, self).refresh_image()
        self.sprite.add_layer('Machinery',util.load_image("images/machinery_40x40.png"))
                 
                
    def update(self,dt):
        super(Machinery, self).update(dt)     
        
        if self.broken:
            if not self.maint_task or self.maint_task.name != ''.join(['Repair ',self.name]):
                self.maint_task = Task(''.join(['Repair ',self.name]), owner = self, timeout=util.seconds(1,'months'), task_duration = util.seconds(4,'hours'), severity='MODERATE', fetch_location_method=Searcher(self,self.installed.station).search,logger=self.logger)
                self.installed.station.tasks.add_task(self.maint_task)
        if self.maint_timer < 0 and ( not self.maint_task or self.maint_task.task_ended() ):
            self.maint_task = Task(''.join(['Maintain ',self.name]), owner = self, timeout=util.seconds(1,'months'), task_duration = util.seconds(1,'hours'), severity='LOW', fetch_location_method=Searcher(self,self.installed.station).search,logger=self.logger)
            #print self.maint_task.timeout,self.maint_task.task_duration
            self.installed.station.tasks.add_task(self.maint_task)
        
        self.maint_timer -= dt
        
    def task_finished(self,task): #TODO add supply usage
        super(Machinery, self).task_finished(task) 
        if not task: return
        if task.name == ''.join(['Maintain ',self.name]) and task.target == self:
            self.maint_task = None
            self.wear += (1 - self.wear) / 2
            self.maint_timer = random.randrange(int (util.seconds(1,'months') * self.wear), int( util.seconds(6,'months') * self.wear ) )
        elif task.name == ''.join(['Repair ',self.name]) and task.target == self:
            self.broken = False
            self.wear += (1 - self.wear) / 2        

    def task_failed(self,task):
        super(Machinery, self).task_failed(task)
        if not task: return
        if task.name == ''.join(['Maintain ',self.name]) and task.target == self:
            self.wear -= 0.05
            if random.random() > self.wear:
                self.broken = True
class DockingComputer(Computer, Rack):
    def __init__(self):
        if not hasattr(self,'imgfile'): self.imgfile = "images/docking_computer.tif"
        super(DockingComputer, self).__init__()              
        self.idle_draw = 0.200 #kW
        self.docking_mode = 'DOCK'
        self.docking_item = None #The thing doing the docking or undocking (THEM)
        self.docking_target = None #The (module,dock) where it will be docking to (US)
        self.docking_path = None #The path object that will interpolate its journey
        self.docking_task = None
        self.docking_duration = util.seconds(2,'minutes')
        self.name = "Docking console"
    
    def refresh_image(self):     
        super(DockingComputer, self).refresh_image()
        if self.sprite is None: return
        self.sprite.add_layer('DockingComputer',util.load_image("images/smalldockingsymbol_40x40.png"))
        
    def dock_module(self,item=[None,None],target=[None, None]):
        if not item[0]: return False
        if not self.installed: return False
        if self.docking_task and not self.docking_task.task_ended(): return False                       
        #TODO check for fuel, engines, etc on item
        
        self.docking_item = item
        self.docking_target = target
        
        if not self.docking_target[0]: 
            mods = self.installed.station.modules     
            self.docking_target[0] = random.choice( [ mods[m] for m in mods if mods[m].get_random_dock() ] )    
        if not self.docking_target[1]: self.docking_target[1] = self.docking_target[0].get_random_dock()                 
        if self.docking_item[0] and not self.docking_item[1]: 
            self.docking_item[1] = self.docking_item[0].get_random_dock(side_port_allowed=False)                                        
        
        self.docking_path = FlightPath(self.docking_target[0], self.docking_target[1], self.docking_item[0], self.docking_item[1],self.docking_duration, FlightType='DOCK')
        
        self.docking_task = Task("Dock module", owner = self, timeout=None, task_duration = self.docking_duration, severity='MODERATE', fetch_location_method=Searcher(self,self.installed.station).search,logger=self.logger)
        self.installed.station.tasks.add_task(self.docking_task)    
        return True

    def undock_module(self, item=[None,None]):
        if not item[0]: return False
        if not self.installed: return False
        if self.docking_task and not self.docking_task.task_ended(): return False                       
        #TODO check for fuel, engines, etc on item
        
        self.docking_item = item
        
        if self.docking_item[0] and not self.docking_item[1]: 
            self.docking_item[1] = self.docking_item[0].get_neighbor_dock(self.installed.station) #TODO this WILL crash, implement when it does
        #check for hatches closed, start tasks if necessary
        dock = self.docking_item[0].equipment[self.docking_item[1]][3]
        if dock.docked:
            self.docking_item[0].disconnect(self.docking_item[1], dock.partner)    
            return False

        
        #undock stations
        self.installed.station.undock_station(self.docking_item[0].station)
        
        #start motion
        new_loc, new_orient = self.installed.station.get_safe_distance_orient()
        new_loc *= 2
        self.docking_path = FlightPath(self.docking_item[0], self.docking_item[1], new_loc, new_orient,self.docking_duration, FlightType='UNDOCK')
        
        self.docking_task = Task("Undock module", owner = self, timeout=None, task_duration = self.docking_duration, severity='MODERATE', fetch_location_method=Searcher(self,self.installed.station).search,logger=self.logger)
        self.installed.station.tasks.add_task(self.docking_task)    
        
        return True

    def task_finished(self,task):
        super(DockingComputer, self).task_finished(task)       
        if not task or not self.installed: return
        if task.name == "Dock module":
            self.docking_item[0].location, self.docking_item[0].orientation = self.docking_path.get_time_point(task.task_duration)
            self.docking_item[0].station.percolate_location(self.docking_item[0])
            self.docking_item[0].refresh_image()
            
            self.installed.station.dock_module(self.docking_target[0], self.docking_target[1], self.docking_item[0], self.docking_item[1])        
            self.docking_item[0].station.position='Docked'
        if task.name == "Undock module":            
            self.docking_item[0].station.position='Approach'
            
            
    def task_work_report(self,task,dt):
        if task.name.startswith('Dock module') or task.name.startswith('Undock module'):
            self.docking_item[0].location, self.docking_item[0].orientation = self.docking_path.get_time_point(task.task_duration - task.task_duration_remaining)
            self.docking_item[0].station.percolate_location(self.docking_item[0])
            self.docking_item[0].refresh_image()
class MissionComputer(Computer, Rack):
    def __init__(self, scenario=None):
        super(MissionComputer, self).__init__()              
        self.idle_draw = 1.000 #kW
        self.scenario=scenario
        
        self.mission = None
        self.objective = None
        self.objective_timer = 30
        self.objective_tick = 30
        
        self.name = "Mission console"
    
    def refresh_image(self):     
        super(MissionComputer, self).refresh_image()
        if self.sprite is None: return
        self.sprite.add_layer('DockingComputer',util.load_image("images/smallmissionsymbol_40x40.png"))
        
    def update(self,dt):            
        super(MissionComputer, self).update(dt)                
        if not self.installed or not self.mission: return
        if not self.objective:             
            self.mission = None
            return
                
        if self.objective.completed and (not self.task or self.task.task_ended()):     
            #print self.objective.name
            self.logger.info(''.join(['Mission objective completed: ',self.objective.name,' Updating mission...']))
            self.task = Task(''.join(['Update Mission']), owner = self, timeout=None, task_duration = 30, severity='MODERATE', fetch_location_method=Searcher(self,self.installed.station).search,logger=self.logger)
            self.installed.station.tasks.add_task(self.task) 
            self.objective_timer = 30
        
        self.objective_tick -= dt        
        if self.objective_tick < 0:
            self.objective_tick = self.objective_timer           
            if not self.objective.completed:                 
                self.objective.carry_out(station=self.installed.station, scenario=self.scenario)
                self.objective_timer += 30
            else:
                self.objective_timer = 30            
            
    def generate_mission(self, selection='New Module', target_id = '', module_id = ''):
        new_miss = mission.Mission()
        new_miss.load_mission( selection=selection, target_id=target_id, module_id=module_id)
        self.new_mission(new_miss)       
            
    def new_mission(self,mission):
        if not mission or (self.task and not self.task.task_ended()) or not self.installed: return
        self.task = Task(''.join(['Log Mission']), owner = self, timeout=None, task_duration = 30, severity='HIGH', fetch_location_method=Searcher(self,self.installed.station).search,logger=self.logger)            
        self.task.mission=mission
        self.installed.station.tasks.add_task(self.task)       
        
    def task_finished(self,task):
        super(MissionComputer, self).task_finished(task)  
        if not task or not self.installed: return
        if task.name == "Log Mission":
            self.mission = self.task.mission 
            self.objective = self.mission.current_objective()
        elif task.name == "Update Mission":                              
            self.objective = self.mission.current_objective()
            if not self.objective: return
            self.objective.carry_out(station=self.installed.station, scenario=self.scenario)
            self.logger.info(''.join(['Mission updated.  Current objective: ',self.objective.name]))
            
        self.update(0)
class DockingRing(Equipment):
    def __init__(self):   
        if not hasattr(self,'imgfile'): self.imgfile = "images/closed_hatch.tif"
        self.open = False
        self.player_usable = True #toggle to allow player to "turn off" hatches
        super(DockingRing, self).__init__()     
        self.docked = None #a pointer to the module we've docked to        
        self.in_vaccuum = True
        self.partner = None #a pointer to the docking equipment partner
                
    def toggle_player_usable(self):
        self.player_usable = not self.player_usable            
        self.refresh_image()
        
    def refresh_image(self):     
        super(DockingRing, self).refresh_image()
        if self.sprite is None: return
        if self.open:
            self.sprite.add_layer('DockingRing',util.load_image("images/open_hatch.png"))
        else:
            self.sprite.add_layer('DockingRing',util.load_image("images/closed_hatch.png"))
        
        #import pyglet
        #img1=pyglet.image.AnimationFrame(util.load_image("images/blank_40x40.png"),0.5 if not self.player_usable else None)
        #img2=pyglet.image.AnimationFrame(util.load_image("images/half_red.png"),0.5)
        
        #animation = pyglet.image.Animation([img1,img2])
        
        if self.player_usable:
            self.sprite.add_layer('Forbidden',util.load_image("images/blank_40x40.png"))
        else:
            self.sprite.add_layer('Forbidden',util.load_image("images/half_red.png"))
        
        self.sprite.layer['Equipment'].visible=False    
        
    #these two need to generate tasks for unpowered rings
    def open_(self):
        if self.open: return
        if not self.docked: return False, "What are you, nuts?!"
        self.open = True
        self.refresh_image()
        if self.partner and not self.partner.open:
            self.installed.station.paths.add_edge(self.installed.get_node(self),self.docked.get_node(self.partner),weight=1)
            self.partner.installed.station.paths.add_edge(self.installed.get_node(self),self.docked.get_node(self.partner),weight=1)
        
    def close_(self):
        if not self.open: return
        self.open=False
        self.refresh_image()
        if self.partner and not self.partner.open:            
            self.installed.station.paths.remove_edge(self.installed.get_node(self),self.docked.get_node(self.partner))
            self.partner.installed.station.paths.remove_edge(self.installed.get_node(self),self.docked.get_node(self.partner))
        
    def dock(self, target, partner=None, instant = False):
        self.docked=target                
        self.in_vaccuum = False
        self.partner=partner
        if instant:             
            self.open_()
        else:
            if not self.installed.station: return
            self.task = Task(''.join(['Open Hatch']), owner = self, timeout=None, task_duration = 300, severity='MODERATE', fetch_location_method=Searcher(self,self.installed.station).search,logger=self.logger)            
            self.installed.station.tasks.add_task(self.task)            
                
    def undock(self, instant = False):
        if not self.open: 
            self.docked = None
            self.in_vaccuum = True
            self.partner = None
            return True
        if self.task and not self.task.task_ended():
            return False
        if instant:
            self.close_()                
        else:
            #TODO check and add a task for disconnecting the pipes
            self.task = Task(''.join(['Close Hatch']), owner = self, timeout=86400, task_duration = 300, severity='LOW', fetch_location_method=Searcher(self,self.installed.station).search,logger=self.logger)
            self.installed.station.tasks.add_task(self.task)
        return self.undock(instant)
            
        
    def task_finished(self,task):
        super(DockingRing, self).task_finished(task) 
        if task.name == 'Close Hatch': 
            #TODO check for someone in the other module
            if self.partner: self.partner.close_()
            if self.open: self.close_()
        elif task.name == 'Open Hatch':
            if not self.open: self.open_()
            if self.partner: self.partner.open_()
            #TODO add a task to connect pipes, open other side
            
    def task_work_report(self,task,dt):
        if task.name == 'Close Hatch' and not self.open: 
            self.task.flag('COMPLETED')
        elif task.name == 'Open Hatch' and self.open:    
            self.task.flag('COMPLETED')
class Machinery(Equipment): #ancestor class for things that need regular maintenance
    def __init__(self):
        self.active = False
        super(Machinery, self).__init__()              
        self.idle_draw = 0.001 #kW
        #self.maint_timer = random.randrange(util.seconds(6,'months'), util.seconds(2,'years') )
        self.maint_task = None
        self.operating_time_since_last_maintenance = 0
        self.maintenance_interval = util.seconds(7,'days')
        self.wear = 1.0
        self.broken = False
        self.recently_active=False
        self.type = 'MACHINERY'
            
    def refresh_image(self):     
        super(Machinery, self).refresh_image()
        if self.sprite is None: return
        import pyglet
        img1=pyglet.image.AnimationFrame(util.load_image("images/machinery_40x40.png"),0.5 if self.active else None)
        img2=pyglet.image.AnimationFrame(util.load_image("images/machinery_40x40_1.png"),0.5)
        
        animation = pyglet.image.Animation([img1,img2])
        
        self.sprite.add_layer('Machinery',animation)                                                 
        
    def set_active(self):
        #TODO figure out why the below line doesn't work
        self.sprite.layer['Machinery'].image.frames[0].duration=0.5 if self.recently_active else None        
                
    def update(self,dt):
        super(Machinery, self).update(dt)     
  
        if self.active: 
            if not self.recently_active:
                self.recently_active = True
                self.refresh_image()
                #self.set_active()
            
            self.operating_time_since_last_maintenance += dt
            if random.random() < (dt/util.seconds(1,'month'))*self.operating_time_since_last_maintenance/(100*self.wear*self.maintenance_interval):
                self.broken = True
        else:
            if self.recently_active:
                self.recently_active = False
                #self.set_active()
                self.refresh_image()
            
        if self.broken:
            if not self.maint_task or self.maint_task.name != ''.join(['Repair ',self.name]):
                self.maint_task = Task(''.join(['Repair ',self.name]), owner = self, timeout=None, task_duration = util.seconds(4,'hours'), severity='MODERATE', fetch_location_method=Searcher(self,self.installed.station).search,logger=self.logger)
                self.installed.station.tasks.add_task(self.maint_task)  
                
        if self.operating_time_since_last_maintenance >= self.wear*self.maintenance_interval and ( not self.maint_task or self.maint_task.task_ended() ):
            self.maint_task = Task(''.join(['Maintain ',self.name]), owner = self, timeout=None, task_duration = util.seconds(1,'hours'), severity='LOW', fetch_location_method=Searcher(self,self.installed.station).search,logger=self.logger)
            #print self.maint_task.timeout,self.maint_task.task_duration
            self.installed.station.tasks.add_task(self.maint_task)        
        
    def task_finished(self,task): #TODO add supply usage
        super(Machinery, self).task_finished(task) 
        if not task: return
        if task.name == ''.join(['Maintain ',self.name]) and task.target == self:
            self.maint_task = None
            self.wear -= self.operating_time_since_last_maintenance/(self.wear*self.maintenance_interval) - 1
            print self.operating_time_since_last_maintenance, self.wear, self.maintenance_interval
            self.wear = max(self.wear,0)
            self.operating_time_since_last_maintenance = 0
        elif task.name == ''.join(['Repair ',self.name]) and task.target == self:
            self.maint_task = None
            self.broken = False
            self.wear += (1 - self.wear) / 2