local _ENV = mkmodule('plugins.dwarfmonitor')

local gps = df.global.gps
local gui = require 'gui'

config = {}
widgets = {}

function dmerror(desc)
    qerror('dwarfmonitor: ' .. tostring(desc))
end

Widget = defclass(Widget)
function Widget:init(opts)
    self.opts = opts
end
function Widget:get_pos()
    local x = self.opts.x >= 0 and self.opts.x or gps.dimx + self.opts.x
    local y = self.opts.y >= 0 and self.opts.y or gps.dimy + self.opts.y
    if self.opts.anchor == 'right' then
        x = x - (self:get_width() or 0) + 1
    end
    return x, y
end
function Widget:render()
    if monitor_state(self.opts.type) == false then
        return
    end
    self:update()
    local x, y = self:get_pos()
    local p = gui.Painter.new_xy(x, y, gps.dimx - 1, y)
    self:render_body(p)
end
function Widget:update() end
function Widget:get_width() end
function Widget:render_body() end

Widget_weather = defclass(Widget_weather, Widget)

function Widget_weather:update()
    self.counts = get_weather_counts()
end

function Widget_weather:get_width()
    if self.counts.rain > 0 then
        if self.counts.snow > 0 then
            return 9
        end
        return 4
    elseif self.counts.snow > 0 then
        return 4
    end
    return 0
end

function Widget_weather:render_body(p)
    if self.counts.rain > 0 then
        p:string('Rain', COLOR_LIGHTBLUE):advance(1)
    end
    if self.counts.snow > 0 then
        p:string('Snow', COLOR_WHITE)
    end
end

Widget_date = defclass(Widget_date, Widget)
Widget_date.ATTRS = {
    output = ''
}

function Widget_date:update()
    if not self.opts.format then
        self.opts.format = 'Y-M-D'
    end
    local year = dfhack.world.ReadCurrentYear()
    local month = dfhack.world.ReadCurrentMonth() + 1
    local day = dfhack.world.ReadCurrentDay()
    self.output = 'Date:'
    for i = 1, #self.opts.format do
        local c = self.opts.format:sub(i, i)
        if c == 'y' or c == 'Y' then
            self.output = self.output .. year
        elseif c == 'm' or c == 'M' then
            if c == 'M' and month < 10 then
                self.output = self.output .. '0'
            end
            self.output = self.output .. month
        elseif c == 'd' or c == 'D' then
            if c == 'D' and day < 10 then
                self.output = self.output .. '0'
            end
            self.output = self.output .. day
        else
            self.output = self.output .. c
        end
    end
end

function Widget_date:get_width()
    return #self.output
end

function Widget_date:render_body(p)
    p:string(self.output, COLOR_GREY)
end

Widget_misery = defclass(Widget_misery, Widget)

function Widget_misery:update()
    self.data = get_misery_data()
end

function Widget_misery:get_width()
    local w = 2 + 6
    for k, v in pairs(self.data) do
        w = w + #tostring(v.value)
    end
    return w
end

function Widget_misery:render_body(p)
    p:string("H:", COLOR_WHITE)
    for i = 0, 6 do
        local v = self.data[i]
        p:string(tostring(v.value), v.color)
        if not v.last then
            p:string("/", COLOR_WHITE)
        end
    end
end

Widget_cursor = defclass(Widget_cursor, Widget)

function Widget_cursor:update()
    if gps.mouse_x == -1 and not self.opts.show_invalid then
        self.output = ''
        return
    end
    self.output = (self.opts.format or '(x,y)'):gsub('[xX]', gps.mouse_x):gsub('[yY]', gps.mouse_y)
end

function Widget_cursor:get_width()
    return #self.output
end

function Widget_cursor:render_body(p)
    p:string(self.output)
end

function render_all()
    for _, w in pairs(widgets) do
        w:render()
    end
end

function load_config()
    config = require('json').decode_file('dfhack-config/dwarfmonitor.json')
    if not config.widgets then
        dmerror('No widgets enabled')
    end
    if type(config.widgets) ~= 'table' then
        dmerror('"widgets" is not a table')
    end
    widgets = {}
    for _, opts in pairs(config.widgets) do
        if type(opts) ~= 'table' then dmerror('"widgets" is not an array') end
        if not opts.type then dmerror('Widget missing type field') end
        local cls = _ENV['Widget_' .. opts.type]
        if not cls then
            dmerror('Invalid widget type: ' .. opts.type)
        end
        table.insert(widgets, cls(opts))
    end
end

return _ENV
