view ClassPlan.lua @ 2:b8a19781f79b

shipment logging
author Nenue
date Thu, 13 Oct 2016 09:08:38 -0400
parents 232617b8bcd5
children c006ce87a147
line wrap: on
line source
local wipe = table.wipe
local pairs, ipairs = pairs, ipairs
local GetTime = GetTime
local blockTemplate = {
  point = 'TOPLEFT',
  relativePoint ='TOPLEFT',
}

SLASH_CLASSPLAN1 = "/classplan"
SLASH_CLASSPLAN2 = "/cp"
SlashCmdList.CLASSPLAN = function(args)
  if ClassOrderPlan:IsVisible() then
    ClassOrderPlan:Hide()
  else
    ClassOrderPlan:Show()
    DEFAULT_CHAT_FRAME:AddMessage('|cFF88FF00WorldPlan|r: Order Hall Panel')
  end
end

ClassOrderPlanCore = {
  freeBlocks = {},
  blocks = {},
  shipmentBlocks = {},
  freeShipmentBlocks = {},
  sortedShipments = {},
  sortedMissions = {},
  timers = {},
  shipments = {},
  playerFirst = false,
  templates = setmetatable({}, {
    __newindex = function(t,k ,v)
      if type(v) == 'table' then
        setmetatable(v, {__index = blockTemplate})
        rawset(t,k,v)
      end
    end
  })
}
ClassPlanBlockMixin = {}
ClassPlanShipmentMixin = setmetatable({}, {__index = ClassPlanBlockMixin})
local core, block, shipment = ClassOrderPlanCore, ClassPlanBlockMixin, ClassPlanShipmentMixin
local print = DEVIAN_WORKSPACE and function(...) print('ClassPlan', ...) end or nop



function core:OnLoad ()
  self:RegisterUnitEvent('UNIT_PORTRAIT_UPDATE', 'player')
  self:RegisterEvent('PLAYER_LOGIN')
  self:RegisterEvent('PLAYER_ENTERING_WORLD')
  self:RegisterEvent('PLAYER_REGEN_ENABLED')

  self:RegisterEvent('GARRISON_MISSION_LIST_UPDATE')
  self:RegisterEvent('GARRISON_MISSION_FINISHED')
  self:RegisterEvent("GARRISON_LANDINGPAGE_SHIPMENTS");
  self:RegisterEvent("GARRISON_SHIPMENT_RECEIVED");
  self:RegisterEvent("GARRISON_TALENT_UPDATE");
  self:RegisterEvent("GARRISON_TALENT_COMPLETE");
end

core.templates.ClassPlanBlock = {
  SetItemData = function(block, data)
    block.isComplete = data.isComplete
    block.missionEndTime = data.missionEndTime
  end
}

core.templates.ClassPlanShipment = {

  parent = false,
  point = 'TOPRIGHT',
  relativePoint ='TOPRIGHT',
  SetItemData = function(block, data)
    block.icon = data.icon
    block.shipmentCapacity = data.shipmentCapacity
    block.shipmentsReady = data.shipmentsReady
    block.shipmentsTotal = data.shipmentsTotal
    block.creationTime = data.creationTime
    block.duration = data.duration
    block.itemID = data.itemID
    block.itemQuality = data.itemQuality
    --[[
        icon = texture,
        shipmentCapacity = shipmentCapacity,
        shipmentsReady = shipmentsReady,
        shipmentsTotal = shipmentsTotal,
        creationTime = creationTime,
        duration = duration,
        timeleftString = timeleftString,
        itemName = itemName,
        itemIcon = itemIcon,
        itemQuality = itemQuality,
        itemID = itemID

    --]]
  end
}

function core:OnEvent (event, ...)
  print(event)
  if event == 'UNIT_PORTRAIT_UPDATE' then
    SetPortraitTexture(self.portrait, 'player')
  elseif event == 'PLAYER_LOGIN' then
    if not self.initialized then
      if IsLoggedIn() then
        WorldPlanData.OrderHall = WorldPlanData.OrderHall or {}
        self.data = WorldPlanData.OrderHall


        local name, realm = UnitName('player')
        realm  = realm or GetRealmName()
        self.profileKey = name .. '-' .. realm
        if not self.data[self.profileKey] then
          self.data[self.profileKey] = {}
        end
        self.profile = self.data[self.profileKey]

        self.profile.shipments = self.profile.shipments or {}
        self.profile.missions = self.profile.missions or {}
        self.profile.classColor = RAID_CLASS_COLORS[select(2, UnitClass('player'))]

        C_Garrison.RequestLandingPageShipmentInfo();
        self.initialized = true
      end
    end
  elseif event == 'GARRISON_LANDINGPAGE_SHIPMENTS' or event == 'GARRISON_TALENT_UPDATE' then
    self:UpdateShipments()
  elseif event == 'PLAYER_REGEN_ENABLED' or event == 'GARRISON_MISSION_FINISHED' or event == 'GARRISON_TALENT_COMPLETE' or event == 'GARRISON_SHIPMENT_RECEIVED' then
    self:UpdateNotifications()
  else
    self:UpdateItems ()
  end
end

function core:UpdateNotifications()
end

function core:RefreshItems(sortedItems, templateName)
  self.blocks[templateName] = self.blocks[templateName] or {}
  local blocks = self.blocks[templateName]
  local template = self.templates[templateName] or {
    parent = self.portrait,
    point = 'TOPLEFT',
    relativePoint ='TOPRIGHT',
  }

  local lastProfile
  local numItems = #sortedItems
  for i, data in ipairs(sortedItems) do
    local block = blocks[i]

    if not block then
      block = CreateFrame('Frame', nil, self, templateName)
      block:SetID(i)
      template.numBlocks = (template.numBlocks or 0) + 1

      if template.lastBlock then
        block:SetPoint('TOPLEFT', template.lastBlock, 'BOTTOMLEFT', 0, 0)
      else
        block:SetPoint(template.point, self[template.parent] or self, template.relativePoint, 0, 0)
      end
      template.lastBlock = block
      blocks[i] = block
    end

    if template.SetItemData then
      template.SetItemData(block, data)
    end


    block.lastProfile = lastProfile
    block:Refresh(data)
    block:Show()
    lastProfile = data.profileKey
  end

  for i = numItems + 1, template.numBlocks do
    if blocks[i] then
      blocks[i]:Hide()
    end
  end
end

function core:Refresh()
  if self.isStale then
    self:SortLists()
  end
  self.isStale = nil

  self:RefreshItems(self.sortedMissions, 'ClassPlanBlock')
  self:RefreshItems(self.sortedShipments, 'ClassPlanShipment')


  local posX = self.data.posX or 0
  local posY = self.data.posY or -24
  local point = self.point or 'TOP'
  local relativePoint = self.point or 'TOP'
  self:SetPoint(point, UIParent, relativePoint, posX, posY)


end

function core:OnUpdate()
  if self.fadeTimer and self.fadeTimer < GetTime() then
    self:Hide()
  end
end

function core:OnShow()
  if self.isStale then
    print('updating items on show')
    self:Refresh()
  end

end

function core:SortLists()

  wipe(self.sortedShipments)
  wipe(self.sortedMissions)
  for name, profile in pairs(self.data) do
    local isMine = (profile == self.profile)
    for index, data in pairs(profile.missions) do

      data.classColor = profile.classColor or {r = 0.7, g = 0.7, b =0.7}
      data.profileKey = name
      data.isMine = (profile == self.profile)
      tinsert(self.sortedMissions, data)
    end

    if not profile.shipments then
      profile.shipments = {}
      profile.shipment = nil
    end

    for index, data in pairs(profile.shipments) do
      data.classColor = profile.classColor or {r = 0.7, g = 0.7, b =0.7}
      data.profileKey = name
      data.isMine = (profile == self.profile)
      tinsert(self.sortedShipments, data)
    end
  end

  table.sort(self.sortedMissions, function (a,b)
    local result = false
    if not a or not b then
      result = true
    else
      if (a.isMine ~= b.isMine) and self.playerFirst then
        result =  a.isMine
      else
        if (not b.missionEndTime) or (not a.missionEndTime) then
          print('missing article', b.missionEndTime, a.missionEndTime)
        end
        result = ( b.missionEndTime > a.missionEndTime)
      end
    end

    --print('cmp', (b and (b.missionEndTime .. ' ' .. tostring(b.isMine)) or '-'), '>', (a and (a.missionEndTime .. ' ' .. tostring(a.isMine)) or '-'), result, n)
    return result
  end)

end

function core:UpdateShipments()
  print('|cFF0088FFShipments|r:', self.profileKey)
  if not self.profile then
    return
  end
  wipe(self.shipments)


  local garrisonType = LE_GARRISON_TYPE_7_0
  local buildings = C_Garrison.GetBuildings(garrisonType);
  local shipmentIndex = 0
  print('Buildings:')
  for i = 1, #buildings do
    local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, itemName, itemIcon, itemQuality, itemID = C_Garrison.GetLandingPageShipmentInfo(buildingID);
    print(buildings[i], name, creationTime, duration)
    tinsert(self.shipments,
      {
        shipmentType = 'Work Order',
        name = name,
        icon = texture,
        shipmentCapacity = shipmentCapacity,
        shipmentsReady = shipmentsReady,
        shipmentsTotal = shipmentsTotal,
        creationTime = creationTime,
        duration = duration,
        timeleftString = timeleftString,
        itemName = itemName,
        itemIcon = itemIcon,
        itemQuality = itemQuality,
        itemID = itemID
      })
  end

  print('Follower:')
  local followerShipments = C_Garrison.GetFollowerShipments(garrisonType);
  for i = 1, #followerShipments do
    local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, _, _, _, _, followerID = C_Garrison.GetLandingPageShipmentInfoByContainerID(followerShipments[i]);
    print(followerShipments[i], name, creationTime, duration)
    tinsert(self.shipments,
      {
        shipmentType = '',
        name = name,
        icon = texture,
        shipmentCapacity = shipmentCapacity,
        shipmentsReady = shipmentsReady,
        shipmentsTotal = shipmentsTotal,
        creationTime = creationTime,
        duration = duration,
        timeleftString = timeleftString,
        followerID = followerID,
      })
  end

  print('Loose:')
  local looseShipments = C_Garrison.GetLooseShipments(garrisonType)
  for i = 1, #looseShipments do
    local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString = C_Garrison.GetLandingPageShipmentInfoByContainerID(looseShipments[i]);
    print(looseShipments[i], name, creationTime, duration)
    tinsert(self.shipments,
      {
        shipmentType = '',
        name = name,
        icon = texture,
        shipmentCapacity = shipmentCapacity,
        shipmentsReady = shipmentsReady,
        shipmentsTotal = shipmentsTotal,
        creationTime = creationTime,
        duration = duration,
        timeleftString = timeleftString,
      })
  end

  local talentTrees = C_Garrison.GetTalentTrees(garrisonType, select(3, UnitClass("player")));
  -- this is a talent that has completed, but has not been seen in the talent UI yet.
  local completeTalentID = C_Garrison.GetCompleteTalent(garrisonType);
  print('Talents:')
  if (talentTrees) then
    for treeIndex, tree in ipairs(talentTrees) do
      for talentIndex, talent in ipairs(tree) do
        local showTalent = false;
        if (talent.isBeingResearched) then
          showTalent = true;
        end
        if (talent.id == completeTalentID) then
          showTalent = true;
        end
        if (showTalent) then
          print(talent.name)
          talent.creationTime = talent.researchStartTime
          talent.duration = talent.researchDuration
          talent.shipmentType = 'Talent: '
          tinsert(self.shipments, talent)
        end
      end
    end
  end

  self.profile.shipments = self.profile.shipments or {}
  if #self.shipments >= 1 then

    wipe(self.profile.shipments)
    for index, shipment in ipairs(self.shipments) do
      tinsert(self.profile.shipments, shipment)
    end
    self.isStale = true
  end

  if self:IsVisible() then
    self:Refresh()
  end
end

function core:UpdateItems ()
  if not self.profile then
    return
  end
  self.items = C_Garrison.GetLandingPageItems(LE_GARRISON_TYPE_7_0)




  print('|cFF0088FFLandingPageItems|r:', self.profileKey)
  if #self.items >= 1 then
    wipe(self.profile.missions)
    for index, data in ipairs(self.items) do
      print('', data.name)
      print('  |cFF00FF00', data.timeLeft .. '|r', date("%A %I:%m %p", data.missionEndTime))
      tinsert(self.profile.missions, data)
    end
    print('items update pending')
    self.isStale = true
  end

  if self:IsVisible() then
    self:Refresh()
  end
end

function block:OnComplete()
  self.isComplete = true
  self:Refresh()
end

local GetTimeLeftString = function(timeLeft)

  local days = floor(timeLeft/(24*3600))
  local hours = floor(mod(timeLeft, (24*3600)) / 3600)
  local minutes = floor(mod(timeLeft, 3600) / 60)
  local seconds = mod(timeLeft, 60)
  if days >= 1 then
    return (days .. 'd' .. ' ') .. ((hours > 0) and (hours .. 'h ') or '')
  else
    return ((hours > 0) and (hours .. 'h ') or '') .. ((minutes > 0) and (minutes .. ' min') or '')
  end
end

function block:OnUpdate()
  if self.isComplete then
    return
  end

  if self.missionEndTime then
    local timeLeft = self.missionEndTime - time()
    if timeLeft < 0 then
      self:OnComplete()
    else
      self.TimeLeft:SetText(GetTimeLeftString(timeLeft))

      if timeLeft > 3600 then
        self.TimeLeft:SetTextColor(1,1,1)
      else
        self.TimeLeft:SetTextColor(1,1,0)
      end

    end
  else
    self.TimeLeft:SetText(self.missionEndTime)
  end
end

local SetClassColors = function(self, data)

  if self.lastProfile ~= data.profileKey then
    self.Owner:SetText(data.profileKey)
    self.Owner:SetTextColor(data.classColor.r, data.classColor.g, data.classColor.b)
  else
    self.Owner:SetText(nil)
  end
  self.Background:SetColorTexture(data.classColor.r, data.classColor.g, data.classColor.b,
    (data.isComplete and 0.5 or 0.1))
end

function block:Refresh(data)
  data = data or self.data
  self.data = data

  local r,g,b = 1, 1, 1
  if data.isRare then
    r,g,b = 0.1, 0.4, 1
  end


  --self.missionData = data
  self.Label:SetText(data.name)
  self.Label:SetTextColor(r, g, b)

  if #data.rewards >= 1 then
    self.Icon:SetTexture(data.rewards[1].icon or GetItemIcon(data.rewards[1].itemID))
    self.rewardInfo = data.rewards[1]
  else
    self.Icon:SetAtlas(data.typeAtlas, false)
  end

  SetClassColors(self, data)

  if self.isComplete then
    self.TimeLeft:SetText('Complete!')
  end
end


function block:OnEnter()
  if self.rewardInfo and self.rewardInfo.itemID then
    GameTooltip:SetOwner(self, 'ANCHOR_LEFT')
    GameTooltip:SetItemByID(self.rewardInfo.itemID)
    GameTooltip:Show()
  end
end
function block:OnLeave()
  if GameTooltip:IsOwned(self) then
    GameTooltip:Hide()
  end
end



function shipment:Refresh(data)
  data = data or self.data
  self.Icon:SetTexture(data.icon)
  self.data = data

  self.Name:SetText(data.shipmentType .. data.name)
  self.Count:SetText(data.shipmentsReady)

  self.Done:SetShown(data.shipmentsReady and (data.shipmentsReady >= 1))

  if ( data.shipmentsReady == data.shipmentsTotal ) then
    self.Swipe:SetCooldownUNIX(0, 0);
    self.Done:Show();
    if not data.isBeingResearched then
      data.isComplete = true
    end
  else
    self.Swipe:SetCooldownUNIX(data.creationTime or 0 , data.duration or 0);
  end



  SetClassColors(self, data)
end
function shipment:UpdateShipment()

  local data = self.data
  if data.shipmentsTotal  then
    local timeLeft = data.creationTime + data.duration - time()
    if timeLeft < 0 then
      local numReady = floor((1*timeLeft) / data.duration)
      data.shipmentsReady = data.shipmentsReady + numReady
      data.creationTime = data.creationTime + (numReady * data.duration)
      self:Refresh()
    end
  end
end
function shipment:OnUpdate()
  local data = self.data
  if (data.shipmentsReady and data.shipmentsTotal) and (data.shipmentsReady ~= data.shipmentsTotal) then
    local timeLeft = data.creationTime + data.duration - time()
    if timeLeft < 0 then
      self:UpdateShipment()
      return
    end

    self.TimeLeft:SetText('Next: '.. GetTimeLeftString(timeLeft) .. ' |cFFFFFF00'..data.shipmentsTotal..' orders|r')


  elseif data.isBeingResearched then
    self.TimeLeft:SetText(GetTimeLeftString(data.researchStartTime + data.researchDuration - time()))
  else
    self.TimeLeft:SetText('Complete!')
  end

end

function shipment:OnEnter()
  local data = self.data
  if ( data.shipmentsReady and data.shipmentsTotal ) then
    GameTooltip:SetOwner(self, 'ANCHOR_LEFT')
    GameTooltip:AddLine(data.shipmentsReady .. ' of '.. data.shipmentsTotal)
    GameTooltip:Show()
  end
end

function shipment:OnLeave()
  if GameTooltip:IsOwned(self) then
    GameTooltip:Hide()
  end
end

function shipment:OnClick(button)
  --todo: trigger cleanup script for dead shipment data
end