setDefaultTab("Main")
-- first, the variables
local launchTime = now
local startExp = exp()
local dmgTable = {}
local healTable = {}
local expTable = {}
local totalDmg = 0
local totalHeal = 0
local dmgDistribution = {}
local first = "-"
local second = "-"
local third = "-"

if not storage.bestHit or type(storage.bestHit) ~= "number" then
    storage.bestHit = 0
end
if not storage.bestHeal or type(storage.bestHeal) ~= "number" then
    storage.bestHeal = 0
end

local resetSessionData = function()
    launchTime = now
    startExp = exp()
    dmgTable = {}
    healTable = {}
    expTable = {}
    totalDmg = 0
    totalHeal = 0
    dmgDistribution = {}
    first = "-"
    second = "-"
    third = "-"
end

function format_thousand(v)
    if not v then return 0 end
    local s = string.format("%d", math.floor(v))
    local pos = string.len(s) % 3
    if pos == 0 then pos = 3 end
    return string.sub(s, 1, pos)
    .. string.gsub(string.sub(s, pos+1), "(...)", ".%1")
  end

local expGained = function()
    return exp() - startExp
end
local expLeft = function()
    local level = lvl()+1
    return math.floor((50*level*level*level)/3 - 100*level*level + (850*level)/3 - 200) - exp()
end

local niceTimeFormat = function(v) -- v in seconds
    local hours = string.format("%02.f", math.floor(v/3600))
    local mins = string.format("%02.f", math.floor(v/60 - (hours*60)))
   return hours .. ":" .. mins .. "h"
end
local sessionTime = function()
    uptime = math.floor((now - launchTime)/1000)
    return niceTimeFormat(uptime)
end

local expPerHour = function(calculation)
    local r = 0
    if #expTable > 0 then
        r = exp() - expTable[1]
    else
        return "-"
    end

    if uptime < 15*60 then
        r = math.ceil((r/uptime)*60*60)
    else
        r = math.ceil(r*8)
    end
    if calculation then
        return r
    else
        return format_thousand(r)
    end
end

local timeToLevel = function()
    local t = 0
    if expPerHour(true) == 0 or expPerHour() == "-" then
        return "-"
    else
        t = expLeft()/expPerHour(true)
        return niceTimeFormat(math.ceil(t*60*60))
    end
end

local sumT = function(t)
    local s = 0
    for i,v in pairs(t) do
        s = s + v.d
    end
    return s
end

local valueInSeconds = function(t)
    local d = 0
    local time = 0
    if #t > 0 then
        for i, v in ipairs(t) do
            if now - v.t <= 3000 then
                if time == 0 then
                    time = v.t
                end
                d = d + v.d
            else
              table.remove(t, 1)
            end
        end
    end
    return math.ceil(d/((now-time)/1000))
end

local regex = "You lose ([0-9]*) hitpoints due to an attack by ([a-z*]) ([a-z A-z-]*)" 
onTextMessage(function(mode, text)
    if mode == 21 then -- damage dealt
      totalDmg = totalDmg + getFirstNumberInText(text)
        table.insert(dmgTable, {d = getFirstNumberInText(text), t = now})
        if getFirstNumberInText(text) > storage.bestHit then
            storage.bestHit = getFirstNumberInText(text)
        end
    end
    if mode == 23 then -- healing
      totalHeal = totalHeal + getFirstNumberInText(text)
        table.insert(healTable, {d = getFirstNumberInText(text), t = now})
        if getFirstNumberInText(text) > storage.bestHeal then
            storage.bestHeal = getFirstNumberInText(text)
        end
    end

    -- damage distribution part
    if text:find("You lose") then
      local data = regexMatch(text, regex)[1]
      if data then
        local monster = data[4]
        local val = data[2]
        table.insert(dmgDistribution, {v=val,m=monster,t=now})
      end
    end
end)


-- tables maintance
macro(500, function()
  local dmgFinal = {}
  local labelTable = {}
  local dmgSum = 0
    table.insert(expTable, exp())
    if #expTable > 15*60 then
        for i,v in pairs(expTable) do
            if i == 1 then
              table.remove(expTable, i)
            end
        end
    end

    for i,v in pairs(dmgDistribution) do
      if now - v.t > 60*1000*10 then
        table.remove(dmgDistribution, i)
      else
        dmgSum = dmgSum + v.v
        if not dmgFinal[v.m] then
          dmgFinal[v.m] = v.v
        else
          dmgFinal[v.m] = dmgFinal[v.m] + v.v
        end
      end
    end

    if not dmgFinal[1] then
      first = "-"
    end
    if not dmgFinal[2] then
      second = "-"
    end
    if not dmgFinal[3] then
      third = "-"
    end

    local iter = 0
    for k,v in pairs(dmgFinal) do
      table.insert(labelTable, {m=k, d=tonumber(v)})
    end

    table.sort(labelTable, function(a,b) return a.d > b.d end)

    for i,v in pairs(labelTable) do
      local label = v.m .. ": " .. math.floor((v.d/dmgSum)*100) .. "%"
      if i == 1 then
        first = label
      elseif i == 2 then
        second = label
      elseif i == 3 then
        third = label
      end
    end
end)

-- visuals
local ui = setupUI([[
Panel
  height: 320
  padding: 5

  BotButton
    id: toggle
    anchors.top: parent.top
    anchors.left: parent.left
    anchors.right: parent.right
    text: Session Analyzer

  BotButton
    id: reset
    anchors.top: prev.bottom
    margin-top: 5
    anchors.left: parent.left
    anchors.right: parent.right
    text: Reset Session

  Label
    id: SessionLabel
    anchors.top: prev.bottom
    margin-top: 3
    anchors.left: parent.left
    text: Session:

  Label
    id: XpGainLabel
    anchors.top: prev.bottom
    anchors.left: parent.left
    margin-top: 5
    text: XP Gain:

  Label
    id: XpHourLabel
    anchors.top: prev.bottom
    anchors.left: parent.left
    margin-top: 5
    text: XP/h:

  Label
    id: NextLevelLabel
    anchors.top: prev.bottom
    anchors.left: parent.left
    margin-top: 5
    text: Next Level:

  Label
    id: BurstDamageLabel
    anchors.top: prev.bottom
    anchors.left: parent.left
    margin-top: 5
    text: Burst Damage: 

  Label
    id: DamageDealtLabel
    anchors.top: prev.bottom
    anchors.left: parent.left
    margin-top: 5
    text: Damage Dealt:

  Label
    id: DPSLabel
    anchors.top: prev.bottom
    anchors.left: parent.left
    margin-top: 5
    text: DPS: 

  Label
    id: BestHitLabel
    anchors.top: prev.bottom
    anchors.left: parent.left
    margin-top: 5
    text: Best Hit:     

  Label
    id: HealingDoneLabel
    anchors.top: prev.bottom
    anchors.left: parent.left
    margin-top: 5
    text: Healing Done: 

  Label
    id: HPSLabel
    anchors.top: prev.bottom
    anchors.left: parent.left
    margin-top: 5
    text: HPS: 

  Label
    id: BestHealLabel
    anchors.top: prev.bottom
    anchors.left: parent.left
    margin-top: 5
    text: Best Heal:
    
  Label
    id: one
    anchors.right: parent.right
    anchors.verticalCenter: SessionLabel.verticalCenter
    text-align: right
    text: 00:00h
    width: 150

  Label
    id: two
    anchors.right: parent.right
    anchors.top: prev.bottom
    margin-top: 5
    text-align: right
    text: 0
    width: 150

  Label
    id: three
    anchors.right: parent.right
    anchors.top: prev.bottom
    margin-top: 5
    text-align: right
    text: -
    width: 150

  Label
    id: four
    anchors.right: parent.right
    anchors.top: prev.bottom
    margin-top: 5
    text-align: right
    text: -
    width: 150

  Label
    id: five
    anchors.right: parent.right
    anchors.top: prev.bottom
    margin-top: 5
    text-align: right
    text: 0
    width: 150

  Label
    id: six
    anchors.right: parent.right
    anchors.top: prev.bottom
    margin-top: 5
    text-align: right
    text: -
    width: 150

  Label
    id: seven
    anchors.right: parent.right
    anchors.top: prev.bottom
    margin-top: 5
    text-align: right
    text: 0
    width: 150

  Label
    id: eight
    anchors.right: parent.right
    anchors.top: prev.bottom
    margin-top: 5
    text-align: right
    text: 0
    width: 150
    
  Label
    id: nine
    anchors.right: parent.right
    anchors.top: prev.bottom
    margin-top: 5
    text-align: right
    text: 0
    width: 150

  Label
    id: ten
    anchors.right: parent.right
    anchors.top: prev.bottom
    margin-top: 5
    text-align: right
    text: 0
    width: 150

  Label
    id: eleven
    anchors.right: parent.right
    anchors.top: prev.bottom
    margin-top: 5
    text-align: right
    text: 0
    width: 150
  
  HorizontalSeparator
    anchors.top: prev.bottom
    anchors.left: parent.left
    anchors.right: parent.right
    margin-top: 3

  Label
    anchors.top: prev.bottom
    anchors.left: parent.left
    anchors.right: parent.right
    margin-top: 3
    text-align: center
    text: Damage Distribution

  Label
    id: dOne
    anchors.top: prev.bottom
    anchors.left: parent.left
    anchors.right: parent.right
    margin-top: 5
    text-align: center
    text: -

  Label
    id: dTwo
    anchors.top: prev.bottom
    anchors.left: parent.left
    anchors.right: parent.right
    margin-top: 5
    text-align: center
    text: -
    
  Label
    id: dThree
    anchors.top: prev.bottom
    anchors.left: parent.left
    anchors.right: parent.right
    margin-top: 5
    text-align: center
    text: -
]])
ui:setId("analyzers")

local function toggleHeight()
  local h = ui:getHeight()

  if h == 320 then
      ui:setHeight(28)
  else
      ui:setHeight(320)
  end
end
toggleHeight()

ui.reset.onClick = function(widget)
  resetSessionData()
end
ui.toggle.onClick = function(widget)
  toggleHeight()
end

macro(500, function()
    -- refresh part
    ui.one:setText(sessionTime())
    ui.two:setText(format_thousand(expGained()))
    ui.three:setText(expPerHour())
    ui.four:setText(timeToLevel())
    ui.five:setText(format_thousand(burstDamageValue()))
    ui.six:setText(format_thousand(totalDmg))
    ui.seven:setText(format_thousand(valueInSeconds(dmgTable)))
    ui.eight:setText(format_thousand(storage.bestHit))
    ui.nine:setText(format_thousand(totalHeal))
    ui.ten:setText(format_thousand(valueInSeconds(healTable)))
    ui.eleven:setText(format_thousand(storage.bestHeal))
    ui.dOne:setText(first)
    ui.dTwo:setText(second)
    ui.dThree:setText(third)
end)