# -*- coding: utf-8 -*-
"""
Created on Tue Dec 15 09:49:47 2020

@author: james.z.hare
"""

from src.UnitModule import UnitClass, advance
from copy import deepcopy
import math

class ProjectileClass(UnitClass):
    """
    The Projectile Class
    
    This is a subclass to the UnitClass

    Virtual Functions
    -----------------
    - `__copy__()` to make shallow copies
    - `__deepcopy__(memo)` to make deep copies
    - `possibleActions(State)` to identify legal actions
    - `observe(Unit)` to observe units located within VisibleRange
    - `overlaps(Unit)` to identify if the unit overlaps with another unit
    - `execute(Action, State)` to execute the action
    

    Attributes
    ----------
    ID:
        a unique identifier of this unit
    Owner:
        the player the unit belongs to
    Health:
        the health of the unit
    Extent:
        the space occupied by unit
    Position:
        location of unit
    Orientation:
        as the name says
    VisibleRange:
        how far the unit can observe
    Actions: dict
        dictionary of actions common accross all units
    ActionOptions:
        list of list of action options.
    Attack:
        int that defines whether the unit is attacking in an advance action
    RemaingLifetime:
        int that defines the total number of turns until the unit is dead

    """
    
    def __init__(self, ID, Owner, Health, RemainingLifetime=math.inf):
        UnitClass.__init__(self, ID, Owner, Health, Extent=(1,1))
        self.Actions = { "advance": lambda x: advance(self, x) }
        self.ActionOptions = ( ( "advance", ), )
        self.Attack = None
        self.RemainingLifetime = RemainingLifetime

    def __copy__(self):
        Duplicate = ProjectileClass(self.ID, self.Owner, self.Health)
        Duplicate.Position = self.Position
        Duplicate.Orientation = self.Orientation
        Duplicate.Attack = self.Attack
        Duplicate.RemainingLifetime = self.RemainingLifetime
        return Duplicate

    def __deepcopy__(self, memo):
        Default = None
        Exists = memo.get(self, Default)
        if Exists is not Default:
            return Exists
        Duplicate = ProjectileClass(deepcopy(self.ID, memo), deepcopy(self.Owner ,memo), deepcopy(self.Health, memo))
        Duplicate.Position = deepcopy(self.Position, memo)
        Duplicate.Orientation = deepcopy(self.Orientation, memo)
        Duplicate.Attack = deepcopy(self.Attack, memo)
        Duplicate.RemainingLifetime = deepcopy(self.RemainingLifetime, memo)
        memo[self] = Duplicate
        return Duplicate

    def possibleActions(self, State):
        """
        Identifies the set of feasible actions given the board size and position of the unit

        Parameters
        ----------
        State: StateClass

        Returns
        -------
        TrueActions: list[str]
            A list of the feasible actions
        """
        return self.ActionOptions

    def observe(self, Unit):
        if Unit.ID == self.ID:
           return Unit
        return None

    def overlaps(self, Unit):
        MyOccupiedSpace = set([ (self.Position[0]+x, self.Position[1]+y, self.Position[2]) for x in range(self.Extent[0]) for y in range(self.Extent[1]) ])
        #print(Unit)
        TheirOccupiedSpace = set([ (Unit.Position[0]+x, Unit.Position[1]+y, Unit.Position[2]) for x in range(Unit.Extent[0]) for y in range(Unit.Extent[1]) ])
        return len(MyOccupiedSpace.intersection(TheirOccupiedSpace))>0
    
    def execute(self, Actions, State):
        """
        Execute `Actions` on `State`.

        Parameters
        ----------
        Actions : list[str]
            A set of actions to be performed on `State`.
        State : StateClass
            State on which to inflict actions.

        Returns
        -------
        Changes : list
            Resulting state of executed `Actions`.

        """
        NewState = deepcopy(State)
        Changes = []
        for Action in Actions:
            ActionResult = self.Actions[Action](NewState)
            ActionResult[1].RemainingLifetime -= 1
            if isinstance(ActionResult, list):
                Changes += ActionResult
            else:
                Changes.append(ActionResult)
        return Changes

# Will be used as the projectile for the missile launcher unit
class MissileClass(ProjectileClass):
    def __init__(self, ID, Owner, Position, Life=1):
        ProjectileClass.__init__(self, ID, Owner, Positon=Position, Life=Life)
[((56, 8, 56, 65), 'src.UnitModule.UnitClass.__init__', 'UnitClass.__init__', (), '', False, 'from src.UnitModule import UnitClass, advance\n'), ((76, 29, 76, 58), 'copy.deepcopy', 'deepcopy', ({(76, 38, 76, 51): 'self.Position', (76, 53, 76, 57): 'memo'}, {}), '(self.Position, memo)', False, 'from copy import deepcopy\n'), ((77, 32, 77, 64), 'copy.deepcopy', 'deepcopy', ({(77, 41, 77, 57): 'self.Orientation', (77, 59, 77, 63): 'memo'}, {}), '(self.Orientation, memo)', False, 'from copy import deepcopy\n'), ((78, 27, 78, 54), 'copy.deepcopy', 'deepcopy', ({(78, 36, 78, 47): 'self.Attack', (78, 49, 78, 53): 'memo'}, {}), '(self.Attack, memo)', False, 'from copy import deepcopy\n'), ((79, 38, 79, 76), 'copy.deepcopy', 'deepcopy', ({(79, 47, 79, 69): 'self.RemainingLifetime', (79, 71, 79, 75): 'memo'}, {}), '(self.RemainingLifetime, memo)', False, 'from copy import deepcopy\n'), ((126, 19, 126, 34), 'copy.deepcopy', 'deepcopy', ({(126, 28, 126, 33): 'State'}, {}), '(State)', False, 'from copy import deepcopy\n'), ((75, 36, 75, 59), 'copy.deepcopy', 'deepcopy', ({(75, 45, 75, 52): 'self.ID', (75, 54, 75, 58): 'memo'}, {}), '(self.ID, memo)', False, 'from copy import deepcopy\n'), ((75, 61, 75, 87), 'copy.deepcopy', 'deepcopy', ({(75, 70, 75, 80): 'self.Owner', (75, 82, 75, 86): 'memo'}, {}), '(self.Owner, memo)', False, 'from copy import deepcopy\n'), ((75, 89, 75, 116), 'copy.deepcopy', 'deepcopy', ({(75, 98, 75, 109): 'self.Health', (75, 111, 75, 115): 'memo'}, {}), '(self.Health, memo)', False, 'from copy import deepcopy\n'), ((57, 46, 57, 62), 'src.UnitModule.advance', 'advance', ({(57, 54, 57, 58): 'self', (57, 60, 57, 61): 'x'}, {}), '(self, x)', False, 'from src.UnitModule import UnitClass, advance\n')]