library DamageOverTime
	import DamageType
	import Game

	native UnitAlive takes unit u returns boolean

	struct DotData
		unit source    = null
		unit target    = null
		real dps       = 0.
		real duration  = 1.
		string fx      = ""
		integer fxFlag = 0
		integer exFlag = 0
	end

	public struct DamageOverTime
		private static constant real CLOCK_PERIOD = .5

		static constant integer FX_FLAG_ATTACH      = 0
		static constant integer FX_FLAG_COORDS      = 1
		static constant integer NO_EXCLUSIVITY_FLAG = 0

		private static DotData array dotDB
		private static integer dbIndex = -1
		private static timer time = CreateTimer()

		private static method damageTick takes nothing returns nothing
			DotData tempDat
			integer index = 0
			loop
				exitwhen index > dbIndex
				tempDat = dotDB[index]
				if tempDat.fxFlag == FX_FLAG_COORDS then
					DestroyEffect(AddSpecialEffect(tempDat.fx, GetUnitX(tempDat.target), GetUnitY(tempDat.target)))
				elseif tempDat.fxFlag == FX_FLAG_ATTACH then
					DestroyEffect(AddSpecialEffectTarget(tempDat.fx, tempDat.target, "origin"))
				debug else
					debug BJDebugMsg("DamageOverTime.damageTick: Unrecognized fx flag received")
				end

				DamageType.dealCodeDamage(tempDat.source, tempDat.target, tempDat.dps*CLOCK_PERIOD)
				tempDat.duration = tempDat.duration - CLOCK_PERIOD
				if tempDat.duration <= 0. or (not UnitAlive(tempDat.target)) or (not Game.roundEnabled) then
					destroy tempDat
					dotDB[index] = dotDB[dbIndex]
					dbIndex--
					index--
					if dbIndex == -1 then
						PauseTimer(time)
					end
				end
				index++
			end
		end

		static method unitHasFlag takes unit u, integer flag returns boolean
			DotData iterator
			integer index = 0

			loop
				exitwhen index > dbIndex

				iterator = dotDB[index]
				if iterator.target == u and iterator.exFlag == flag then
					return true
				end

				index++
			end

			return false
		end

		static method add takes unit source, unit target, real dps, real duration, string fx, integer fxFlag, integer exclusivityFlag returns nothing
			DotData tempDat

			if exclusivityFlag > 0 and unitHasFlag(target, exclusivityFlag) then
				return
			end

			tempDat = new DotData()

			tempDat.source   = source
			tempDat.target   = target
			tempDat.dps      = dps
			tempDat.duration = duration
			tempDat.fx       = fx
			tempDat.fxFlag   = fxFlag
			tempDat.exFlag   = exclusivityFlag

			dbIndex++
			dotDB[dbIndex] = tempDat
			if dbIndex == 0 then
				TimerStart(time, CLOCK_PERIOD, true, function damageTick)
			end
		end
	end
endlibrary
