class 'M3AbilityLogicBase'
-------------------------------------------------------------------------------
M3AbilityLogicBase.INDICATOR_OFFSET_X = 25
M3AbilityLogicBase.INDICATOR_OFFSET_Y = 25
M3AbilityLogicBase.FRICTION = 0.7
M3AbilityLogicBase.RATIO    = 2
M3AbilityLogicBase.APPEARING_TIME = 0.2

M3AbilityLogicBase.abilityIndicatorUniqueID = 1
-------------------------------------------------------------------------------

function M3AbilityLogicBase:__init(ability, field)
    self.ability   = ability
    self.affectIDs = nil
    self.pField    = field
    self.indicator = nil
    
    self.speed    = Vector2f(0, 0)
    self.effector = nil
    
    self.affectTarget = 1
    self.affectCount  = 0
end
-------------------------------------------------------------------------------

function M3AbilityLogicBase:setAffectIDs(affectIDs)
    if type(affectIDs) == 'table' then
        self.affectIDs = table.copy(affectIDs)
    else
        self.affectIDs = affectIDs
    end
end
-------------------------------------------------------------------------------

function M3AbilityLogicBase:run(spriteInfo, time)
    time = time or M3AbilityLogicBase.APPEARING_TIME
    
    self:_createIndicator(spriteInfo)
    
    if time == 0 then
        self.indicator:setScale(0.5)
    else
        self.effector = CreateAnimationEffector()
        self.effector:setDestroysOnEnd(false)
        self.effector:attachTo(self.indicator)
        self.effector:setKey(_TRACK_O, 0, 0)
        self.effector:setKey(_TRACK_S, 0, 1)
        self.effector:setKey(_TRACK_O, time, 1)
        self.effector:setKey(_TRACK_S, time, 0.5)
        self.effector:play()
    end
end
-------------------------------------------------------------------------------

function M3AbilityLogicBase:stop(time)
    time = time or M3AbilityLogicBase.APPEARING_TIME
    
    if self.effector then
        self.effector:destroy()
        self.effector = nil
    end
    
    if time == 0 then
        self:destroy()
    else
        self.effector = CreateAnimationEffector()
        self.effector:setDestroysOnEnd(false)
        self.effector:attachTo(self.indicator)
        self.effector:setKey(_TRACK_O, 0,    self.indicator:getOpacity())
        self.effector:setKey(_TRACK_O, time, 0)
        self.effector:play()
        
        self.pField.timer:add( function()
                                    self:destroy()
                                end,
                                time)
    end
end
-------------------------------------------------------------------------------

function M3AbilityLogicBase:destroy()
    if self.effector then
        self.effector:destroy()
        self.effector = nil
    end     

    self.indicator:destroy()
    
    self.indicator = nil
    self.pField    = nil
end
-------------------------------------------------------------------------------

function M3AbilityLogicBase:update(dt)
    if self.indicator then
        self:_updateMoveIndicator(dt)
    end
end
-------------------------------------------------------------------------------

function M3AbilityLogicBase:affect(cell)
    self.affectCount = self.affectCount + 1
    
    cell:glow()
end
-------------------------------------------------------------------------------

function M3AbilityLogicBase:canAffect(cell)
    local item = cell:getItem()
    
    return not self.pField.bShuffle    and
            item                       and
            self:isAffectedId(item.id) and
            not item.ability           and
            item:isCalm()
end
-------------------------------------------------------------------------------

function M3AbilityLogicBase:isComplete()
    return self.affectCount >= self.affectTarget
end
-------------------------------------------------------------------------------

function M3AbilityLogicBase:isAffectedId(id)
    if id == self.pField.aimId then
        return false
    end
    
    local result = false
    
    if self.affectIDs == nil then
        result = true
    elseif type(self.affectIDs) == 'table' then
        for i, _id in ipairs(self.affectIDs) do
            if _id == id then
                result = true
                break
            end
        end
    else
        result = (self.affectIDs == id)
    end
    
    return result
end
-------------------------------------------------------------------------------


-------------------------------------------------------------------------------
-- PRIVATE
-------------------------------------------------------------------------------

function M3AbilityLogicBase:_createIndicator(spriteInfo)
    local objectName = 'abilityIndicator'..M3AbilityLogicBase.abilityIndicatorUniqueID
    M3AbilityLogicBase.abilityIndicatorUniqueID = M3AbilityLogicBase.abilityIndicatorUniqueID + 1  

    local anim = CreateSpriteEntity(spriteInfo.texture)
    anim:attachTo(current_scene:getPlayField():getMainEntity())
    anim:setName(objectName) 
    anim:setScrXY(spriteInfo.startScrX, spriteInfo.startScrY)
    anim:setOrder(1000)
    anim:setRespondable(false)

    self.indicator = anim
end
-------------------------------------------------------------------------------

function M3AbilityLogicBase:_updateMoveIndicator(dt)
    local mPos    = getHandledCursor():getPosition()
    local targetX = mPos.x + M3AbilityLogicBase.INDICATOR_OFFSET_X + 171
    local targetY = mPos.y + M3AbilityLogicBase.INDICATOR_OFFSET_Y
    
    local scrX = self.indicator:getScrX()
    local scrY = self.indicator:getScrY()
    
    local dx = (M3AbilityLogicBase.RATIO == 0) and 0 or ((targetX - scrX) / M3AbilityLogicBase.RATIO)
    local dy = (M3AbilityLogicBase.RATIO == 0) and 0 or ((targetY - scrY) / M3AbilityLogicBase.RATIO)
    
    self.speed.x = (self.speed.x + dx) * M3AbilityLogicBase.FRICTION
    self.speed.y = (self.speed.y + dy) * M3AbilityLogicBase.FRICTION
    
    self.indicator:setScrXY(scrX + self.speed.x * dt*10,
                            scrY + self.speed.y * dt*10)
                            
end
-------------------------------------------------------------------------------