local Element = require("gfx.element")
local Prop = require("gfx.prop")
local Orientation = require("gfx.prop.orientation")

local BlankElement = Element:new()

function BlankElement:draw()
  local dirty = Element.draw(self)
  if dirty then
    self:_getWindow().clear()
  end
end

local function round(value, biasDown)
  local decimal = value % 1
  return (((not biasDown) and decimal < 0.5) or ((not not biasDown) and decimal <= 0.5)) and math.floor(value) or math.ceil(value)
end

local Progress = Prop.attach(Element:new{
  progress = 0.0,
  active = nil,
  inactive = nil
}, Orientation, Orientation.HORIZONTAL)

function Progress:new(o)
  local template = o or {}
  template.fgColor = template.fgColor or colors.red
  template.bgColor = template.bgColor or colors.gray

  local obj = Element.new(self, template)
  obj.active = BlankElement:new()
  obj.inactive = BlankElement:new()
  obj:_refreshColors()
  return obj
end

function Progress:setFgColor(color)
  self.active:setBgColor(color)
end

function Progress:setBgColor(color)
  self.inactive:setBgColor(color)
end

function Progress:_updateProgress()
  local width, height = self:getWidth(), self:getHeight()
  if self:isVertical() then
    self.active:resize{
      width = width,
      height = round(self:getProgress() * height)
    }
    self.inactive:resize{
      width = width,
      height = round((1 - self:getProgress()) * height, true)
    }
    self.inactive:setY(self.active:getY() + self.active:getHeight())
  else
    self.active:resize{
      width = round(self:getProgress() * width),
      height = height
    }
    self.inactive:resize{
      width = round((1 - self:getProgress()) * width, true),
      height = height
    }
    self.inactive:setX(self.active:getX() + self.active:getWidth())
  end

  self:_refreshColors()
end

function Progress:_refreshColors()
  self:setFgColor(self:getFgColor())
  self:setBgColor(self:getBgColor())
end

function Progress:setProgress(progress)
  self:setDirty()
  self.progress = math.min(1, math.max(0, progress))
  self:_updateProgress()
end

function Progress:getProgress()
  return self.progress
end

function Progress:draw()
  local dirty = Element.draw(self)
  if dirty then
    self.inactive:draw()
    self.active:draw()
  end
  return dirty
end

function Progress:_isDirty()
  return Element._isDirty(self) or self.active:_isDirty() or self.inactive:_isDirty()
end

function Progress:setDirty(fullInvalidate)
  Element.setDirty(self, fullInvalidate)
  self.active:setDirty(self, fullInvalidate)
  self.inactive:setDirty(self, fullInvalidate)
end

function Progress:_reload()
  Element._reload(self)

  -- Reload child windows
  local win = self:_getWindow()
  self.active:setParent(win)
  self.inactive:setParent(win)
  self:_updateProgress()
end

return Progress