--------------------------------------------------------------------------------
--- Globals
--------------------------------------------------------------------------------
Global("gwtAuraPanel", View.AuraPanel)
Global("gwtTimerTemplate", View.TimerTemplate)

local ignoredBuffs = { }
local redColor = { r = 1.0, g = 0.0, b = 0.0, a = 1.0 }
local yellowColor = { r = 1.0, g = 1.0, b = 0.0, a = 1.0 }
local greenColor = { r = 0.105, g = 0.367, b = 0.078, a = 1.0 }
--------------------------------------------------------------------------------
--- Functions
--------------------------------------------------------------------------------
function Interpolate(color1, color2, color1percent)
  local color2percent = 1.0 - color1percent
  return { 
			r = color1percent * color1.r + color2percent * color2.r, 
			g = color1percent * color1.g + color2percent * color2.g, 
			b = color1percent * color1.b + color2percent * color2.b, 
			a = color1percent * color1.a + color2percent * color2.a 
		 }
end

function ProgressBarChanged(progressBar, percent)
  if percent < 0.0 then
    percent = 0.0
  elseif percent > 1.0 then
    percent = 1.0
  end
  local color
  if percent < 0.5 then
    percent = percent * 2
	color = Interpolate(yellowColor, redColor, percent)
  elseif percent <= 1.0 then
    percent = (percent - 0.5) * 2
	color = Interpolate(greenColor, yellowColor, percent)
  end
  progressBar.backgroundWidget:SetBackgroundColor(color)
end

function ResetIgnoredBuffs()
  for k, v in ignoredBuffs do
    ignoredBuffs[k] = nil
  end
  onEvent["EVENT_OBJECT_BUFFS_CHANGED"]({ objectId = avatar.GetId() })
end

gwtAuraPanel.Items = { }
gwtAuraPanel.HideItems = function(self)
  for k, v in self.Items do
    v.widget:Show(false)
  end
end
gwtAuraPanel.GetItem = function(self, index)
  local result = self.Items[index]
  if result == nil then
    result = { widget = mainForm:CreateWidgetByDesc(gwtSettingsPreview.widget:GetWidgetDesc()) }
    result.Image = result.widget:GetChildChecked("Image", false)
    result.Cooldown = result.widget:GetChildChecked("Cooldown", false)
    result.Stacksize = result.widget:GetChildChecked("Stacksize", false)
    result.ProgressBar = gwtSettingsPreview.ProgressBar:Copy(result.widget:GetChildChecked("ProgressBar", false))	
    gwtAuraPanel.widget:AddChild(result.widget)
    self.Items[index] = result
  end
  return result
end

gwtAuraPanel.UpdateItems = function(self)
  self:HideItems()
  local index = 0
  PlayerStates()
  CleanAuraDataVisibleRecursiveProtect() -- prevent that the addon stop the work, when sometimes here an error raised
  for k, v in auraData do
    index = index + 1	
    local item = self:GetItem(index)	
    v.item = item
	UpdateActiveReference(v)
    local isActive = AuraDataActive(v)
    local isVisible = AuraDataVisible(v)
	--LogInfo(v.name, ": IsActive: ", isActive, ", IsVisible: ", isVisible)
    if v.buff or v.debuff then
      item.widget:Show(isVisible and isActive)
      item.Image:Show(v.showImage)
      item.Stacksize:Show(v.showImage)
      item.Cooldown:Show(v.showTimer)
	  item.ProgressBar.widget:Show(v.showProgressBar)
    elseif v.spellCD or v.itemCD then
      item.widget:Show(isVisible)
      if v.show then
        item.Cooldown:Show(v.showTimer and isActive)
		item.ProgressBar.widget:Show(v.showTimer and isActive)
        item.Image:Show(isActive and v.showImage)
      else
        item.Cooldown:Show(v.showTimer and not isActive)
		item.ProgressBar.widget:Show(v.showProgressBar and not isActive)
        item.Image:Show(isActive and v.showImage)
      end
      item.Stacksize:Show(false)
    end
    item.widget:SetPriority(1000+index)	
    if v.showImage then	  
      if v.useBuffImage then     
        local buffImage = AuraDataTexture(v)        
        if not buffImage then
          item.widget:Show(false)
        else
          item.Image:SetBackgroundTexture(buffImage)
        end
      else
        item.Image:SetBackgroundTexture(pictureList[v.pictureIndex].image)
      end	
    end
    if v.widget ~= item.widget then
      local placement = item.widget:GetPlacementPlain()
      placement.posX = v.posX
      placement.posY = v.posY-20
      placement.sizeX = v.sizeX
      placement.sizeY = v.sizeY+20
      item.widget:SetPlacementPlain(placement)	  
      v.widget = item.widget	  
    end
    if v.opacity == nil then
      v.opacity = 1.0
    end 
    item.widget:SetFade(v.opacity)
  end
end

function SearchBuffs()
  local objects = { }
  for k, v in avatar.GetUnitList() do
    local buffs = { }
	objects[v] = buffs
	for k, v in object.GetBuffs(v) do
	  buffs[v] = true
	end
  end
  local player = avatar.GetId()
  local buffs = { }
  objects[player] = buffs
	for k, v in object.GetBuffs(player) do
	  buffs[v] = true
	end
  onEvent["EVENT_OBJECT_BUFFS_ELEMENT_CHANGED"]({ objects = objects })
end

--------------------------------------------------------------------------------
--- EVENTS
--------------------------------------------------------------------------------
onEvent["EVENT_OBJECT_BUFF_ADDED"] = function(params)
  CreateBuffReferences(params.objectId, nil, object.GetBuffInfo( params.buffId ))
end
onEvent["EVENT_OBJECT_BUFFS_CHANGED"] = function(params)
  for k, v in object.GetBuffs( params.objectId ) do
    RefreshBuffReference(nil, v, params.objectId)
  end
end
onEvent["EVENT_OBJECT_BUFFS_ELEMENT_CHANGED"] = function(params)
  local counter = 0
  for objId, buffs in params.objects do
    for buffId, active in buffs do
      if not ignoredBuffs[buffId] then
        if not RefreshBuffReference(nil, buffId, objId) then
          ignoredBuffs[buffId] = true
        end
      end
    end
  end  
end
onEvent["EVENT_SPELLBOOK_ELEMENT_EFFECT"] = function(params)
  if params.effect == EFFECT_TYPE_COOLDOWN_STARTED then
    AddToCooldown(params.id, "SpellId", params.duration)    
    RefreshSpellCDReference(nil, params.id, params)    
  elseif params.effect == EFFECT_TYPE_COOLDOWN_FINISHED then
    RemoveFromCooldown(params.id)
	RemoveSpellCDReference(params.id, params)
  end
end
onEvent["EVENT_INVENTORY_ITEM_EFFECT"] = function(params)
  params.itemId = avatar.GetInventoryItemId(params.slot)
  if params.effect == EFFECT_TYPE_COOLDOWN_STARTED then
    AddToCooldown(params.itemId, "ItemId", params.duration)
    RefreshItemCDReference(nil, params.itemId, params)	
  elseif params.effect == EFFECT_TYPE_COOLDOWN_FINISHED then    
    RemoveFromCooldown(params.itemId)
	RemoveItemCDReference(params.itemId)
  end
end
onEvent["EVENT_EQUIPMENT_ITEM_EFFECT"] = function(params)
  params.itemId = unit.GetEquipmentItemId(avatar.GetId(), params.slot, params.slotType)
  if params.effect == EFFECT_TYPE_COOLDOWN_STARTED then
    AddToCooldown(params.itemId, "ItemId", params.duration)
    RefreshItemCDReference(nil, params.itemId, params)	    
  elseif params.effect == EFFECT_TYPE_COOLDOWN_FINISHED then
    RemoveFromCooldown(params.itemId)
	RemoveItemCDReference(params.itemId)
  end
end
onEvent["EVENT_UNKNOWN_SLASH_COMMAND"] = function(params)
  if 0 == common.CompareWString(params.text, userMods.ToWString("/paurasreset")) then
    gwtOpenConfig:setPosition(400, 400)
  end
end
View.ToggleVisibility = function() gwtOpenConfig:setPosition(400, 400) end
View.ShowSettings = onReaction[gwtOpenConfig.reactionName]
function UpdateItems()
  gwtAuraPanel:UpdateItems()
end
function ThreeSecondTimer()
  UpdateCurrentlyActive()
  CollectBuffReferences()  
  CollectSpellCDReferences()
  CollectItemCDReferences()
end

local ToWString = userMods.ToWString
local FormatInt = common.FormatInt
local GetEmptyWString = common.GetEmptyWString
local previewCounter = 0
function UpdateDisplayTexts()
  UpdateCachedTimestamp()
  UpdateBuffReferences()
  UpdateSpellCDReferences()
  UpdateItemCDReferences()
  for k, v in auraData do
    local item = v.item
	if item then
	  local progressBar = item.ProgressBar
      if item.Cooldown then		  
		local cooldown = AuraDataCooldown(v)	  
		if cooldown ~= nil then	    
		  item.Cooldown:SetVal("text", ToWString(FormatTimer(cooldown, v.timerFormat)))	
		  if v.showProgressBar then
		    local minimum, maximum = AuraDataProgressRange(v)
		    if minimum and maximum then			  
			  progressBar:setMinimum(minimum)
			  progressBar:setMaximum(maximum)
			  progressBar:setValue(cooldown)
			  item.ProgressBar:Update()
		    end
		  end
		  item.ProgressBar.widget:SetFade(1.0)
		else	   
		  item.ProgressBar.widget:SetFade(0.0)
		  item.Cooldown:SetVal("text", GetEmptyWString())	
		end
      end
      if item.Stacksize then
	    local activeReference = v.activeReference
        if activeReference and activeReference.stackSize and activeReference.stackSize > 1 then
          item.Stacksize:SetVal("text", FormatInt(activeReference.stackSize,"%d"))
        else
          item.Stacksize:SetVal("text", GetEmptyWString())
        end
      end		  
	end
  end

  -- Preview
  previewCounter = previewCounter - 1003
  if previewCounter < 0 then
    previewCounter = previewCounter + 62000
  end  
  gwtSettingsPreview.Cooldown.widget:SetVal("text", userMods.ToWString(FormatTimer(previewCounter, gwtSettingsPreview.Cooldown.timerFormat or "ss.f"))) -- 18745432 represents 05:12:25.432 in milliseconds
  gwtSettingsPreview.ProgressBar:setMinimum(0)
  gwtSettingsPreview.ProgressBar:setMaximum(60000)
  gwtSettingsPreview.ProgressBar:setValue(previewCounter)
  gwtSettingsPreview.ProgressBar:Update()
end
--------------------------------------------------------------------------------
--- Open Button DND
--------------------------------------------------------------------------------
gwtOpenConfig.initDnD = function(self, wtReacting, fUseCfg, fLockedToScreenArea, Padding )
  if not wtReacting then
    wtReacting = self.widget
  end
  DnD:Init(self.DNDID, wtReacting, self.widget, fUseCfg, fLockedToScreenArea, Padding)
end
gwtOpenConfig.show = function(self, visible)
  if(self.isVisible~=visible) then
    self.isVisible=visible   
  end
  self.widget:Show(visible)
end
gwtOpenConfig.DNDID = 145
gwtOpenConfig:initDnD(nil, true, true)
--------------------------------------------------------------------------------
--- INITIALIZATION
--------------------------------------------------------------------------------
gwtSettingsPreview.widget:SetPriority(1200)
gwtSettingsPreview.ProgressBar.onProgressChanged = ProgressBarChanged

View.widget:SetPriority(1500)

CallWhenCharacterAvailable(function()
  local counter = 0	
  StartTimer(gwtTimerTemplate.widget, 100, function()
    counter = counter + 1
    if counter == 3 then      
      counter = 0
      ThreeSecondTimer()
      UpdateItems()
      collectgarbage()
    end
    UpdateDisplayTexts()
  end)
  collectgarbage()
  SearchBuffs()
end)

--LogInfo(Serialize({ Name = "String", Number = 1.337, Integer = 42, WName = userMods.ToWString("String,"), True = true, False = false, 42, 41, 232, 121}))
--LogInfo(Serialize({ ["Hallo="] = "Hey,}" }))
--LogInfo(Serialize({ { "Table1" }, { "Table2" }, "Container" }))



