----------------------------------------------------------------------------------------------------
MixFlyPath = {}

MixFlyPath.AMPLITUDE = 0.15
MixFlyPath.SPEED = 100 -- пикселей / сек
MixFlyPath.FINAL_SCALE = 1.0
MixFlyPath.CLICK_SCALE = 1.3
MixFlyPath.CLICK_SCALE_TIME = 0.4
MixFlyPath.EFFECT_FREQUENCY = 20 -- в секунду

local FLY_EFFECT = "Item_Appear"

----------------------------------------------------------------------------------------------------
function MixFlyPath:new(aElem, aStart, aFinish, aCallback, coeff)
	obj = {}
	setmetatable(obj, self)
	self.__index = self

    if coeff == nil then
        coeff = 1.0
    end
    obj.mCoeff = coeff
	obj.mElement = aElem

	obj.mStart = matrix {{aStart.x}, {aStart.y}, {1}}
	obj.mFinish = matrix {{aFinish.x}, {aFinish.y}, {1}}

    local dx = aFinish.x - aStart.x
	local dy = aFinish.y - aStart.y
	obj.mDistance = math.sqrt(dx * dx + dy * dy)

    obj.mShift = matrix {{1.0, 0.0, aStart.x},
                         {0.0, 1.0, aStart.y},
                         {0.0, 0.0,      1.0}}

    local scale = obj.mDistance
    obj.mScale = matrix {{scale,   0.0, 0.0},
                         {  0.0, scale, 0.0},
                         {  0.0,   0.0, 1.0}}

    local angle = math.atan2(dy, dx)
    local cos = math.cos(angle)
    local sin = math.sin(angle)
    obj.mRotate = matrix {{cos, -sin, 0.0},
                          {sin,  cos, 0.0},
                          {0.0,  0.0, 1.0}}

	obj.mTime = 0.0
	obj.mFlyTime = obj.mDistance / FlyPath.SPEED

    obj.mFlyInitScale = 1.0
    obj.mInitElemScale = 1.0
    obj.mInitElemAngle = 0.0

    if aElem ~= nil then
        obj.mInitElemScale = aElem:getScale()
        obj.mInitElemAngle = aElem:getAngle()
    end

    obj.mCallback = aCallback;

    obj.mLastEffectTime = 0.0

	return obj
end

----------------------------------------------------------------------------------------------------
-- aX E [0, 1]
function MixFlyPath:deviation(aX)
   -- local x = aX / (3.0 * math.pi)
    local x = aX * 2.0 * math.pi
    
    return x * math.sin(x) * MixFlyPath.AMPLITUDE * self.mCoeff--(math.log10(x + 1) - 1) * math.sin(x) * FlyPath.AMPLITUDE
end

----------------------------------------------------------------------------------------------------
function MixFlyPath:term()
    if self.mCallback ~= nil then
        self.mElement:setVisible(scale)
        self.mCallback()
    end
end

----------------------------------------------------------------------------------------------------
function MixFlyPath:update(aElapsed)

    if self.mElement == nil then
        return true
    end

    self.mTime = self.mTime + aElapsed

    if self.mTime < MixFlyPath.CLICK_SCALE_TIME then
        local coef = - (1.7 * self.mTime / MixFlyPath.CLICK_SCALE_TIME - 1) * (1.7 * self.mTime / MixFlyPath.CLICK_SCALE_TIME - 1) + 1
        local scale = self.mInitElemScale + (MixFlyPath.CLICK_SCALE - 1) * self.mInitElemScale * coef
        self.mElement:setScale(scale)
        self.mFlyInitScale = scale
        return false
    end

    if self.mTime > self.mLastEffectTime + 1.0 / MixFlyPath.EFFECT_FREQUENCY then
        self.mLastEffectTime = self.mTime
        start_effect_at(FLY_EFFECT, self.mElement:getPos(true))
    end

    local phase = (self.mTime - MixFlyPath.CLICK_SCALE_TIME) / self.mFlyTime

    if phase > 1.0 then
        if self.mCallback ~= nil then
            self.mCallback()
        end
        return true
    end

    local tDeviation = self:deviation(phase)
    local tPoint = matrix {{phase}, {tDeviation}, {1.0}}
    local tResultPoint = self.mShift:mul(self.mRotate:mul(self.mScale:mul(tPoint)))

    self.mElement:setPos(Vec2(tResultPoint[1][1], tResultPoint[2][1]))

    local elemScale = self.mFlyInitScale * (MixFlyPath.FINAL_SCALE + (1.0 - phase) * (1.0 - MixFlyPath.FINAL_SCALE))
    self.mElement:setScale(elemScale)

    local elemAngle = 2.0 * math.pi * phase + self.mInitElemAngle
    self.mElement:setAngle(elemAngle)

    return false
end