local _ENV = mkmodule('plugins.sort.places')

local sortoverlay = require('plugins.sort.sortoverlay')
local locationselector = require('plugins.sort.locationselector')
local info_overlay = require('plugins.sort.info')
local widgets = require('gui.widgets')
local utils = require('utils')

local info = df.global.game.main_interface.info
local buildings = info.buildings

local zone_names = {
    [df.civzone_type.MeetingHall] = 'Meeting Area',
    [df.civzone_type.Bedroom] = 'Bedroom',
    [df.civzone_type.DiningHall] = 'Dining Hall',
    [df.civzone_type.Pen] = 'Pen Pasture',
    [df.civzone_type.Pond] = 'Pit Pond',
    [df.civzone_type.WaterSource] = 'Water Source',
    [df.civzone_type.Dungeon] = 'Dungeon',
    [df.civzone_type.FishingArea] = 'Fishing',
    [df.civzone_type.SandCollection] = 'Sand',
    [df.civzone_type.Office] = 'Office',
    [df.civzone_type.Dormitory] = 'Dormitory',
    [df.civzone_type.Barracks] = 'Barracks',
    [df.civzone_type.ArcheryRange] = 'Archery Range',
    [df.civzone_type.Dump] = 'Garbage Dump',
    [df.civzone_type.AnimalTraining] = 'Animal Training',
    [df.civzone_type.Tomb] = 'Tomb',
    [df.civzone_type.PlantGathering] = 'Gather Fruit',
    [df.civzone_type.ClayCollection] = 'Clay'
}

-- I used strings rather than df.civzone_type because nobody is going to search "MeadHall" they're going to search "Tavern"
local language_name_types = {
    [df.language_name_type.FoodStore] = 'Inn Tavern',
    [df.language_name_type.Temple] = 'Temple',
    [df.language_name_type.Hospital] = 'Hospital',
    [df.language_name_type.Guildhall] = 'Guildhall',
    [df.language_name_type.Library] = 'Library',
}

local stockpile_settings_flag_names = {
    animals = 'Animal',
    food = 'Food',
    furniture = 'Furniture',
    corpses = 'Corpse',
    refuse = 'Refuse',
    stone = 'Stone',
    ammo = 'Ammo',
    coins = 'Coins',
    bars_blocks = 'Bars/Blocks',
    gems = 'Gems',
    finished_goods = 'Finished Goods',
    leather = 'Leather',
    cloth = 'Cloth',
    wood = 'Wood',
    weapons = 'Weapon',
    armor = 'Armor',
    sheet = 'Sheet'
}

local function get_location_religion(religion_id, religion_type)
    if religion_type == df.religious_practice_type.NONE then return 'Temple'
    else return locationselector.get_religion_string(religion_id, religion_type) or '' end
end

local function get_default_zone_name(zone_type)
    return zone_names[zone_type] or ''
end

local function get_zone_search_key(zone)
    local result = {}

    -- allow zones to be searchable by their name
    if #zone.name == 0 then
        table.insert(result, get_default_zone_name(zone.type))
    else
        table.insert(result, zone.name)
    end

    -- allow zones w/ assignments to be searchable by their assigned unit
    local owner = dfhack.buildings.getOwner(zone)
    if owner then
        table.insert(result, sortoverlay.get_unit_search_key(owner))
    end

    -- allow zones to be searchable by type
    if zone.location_id == -1 then -- zone is NOT a special location and we don't need to do anything special for type searching
        table.insert(result, df.civzone_type[zone.type]);
    else -- zone is a special location and we need to get its type from world data
        local site = dfhack.world.getCurrentSite() or {}
        local building, success = utils.binsearch(site.buildings or {}, zone.location_id, 'id')

        if success and building.name then
            table.insert(result, language_name_types[building.name.type] or '')
            if building.name.has_name then
                table.insert(result, dfhack.translation.translateName(building.name, true))
            end
        end
    end

    -- allow barracks to be searchable by assigned squad
    for _, squad in ipairs(zone.squad_room_info) do
        table.insert(result, dfhack.military.getSquadName(squad.squad_id))
    end

    return table.concat(result, ' ')
end

local function get_location_search_key(zone)
    local site = dfhack.world.getCurrentSite() or {}
    local result = {}

    -- get language_name and type (we dont need user-given zone name because it does not appear on this page)
    local building, success = utils.binsearch(site.buildings or {}, zone.location_id, 'id')
    if success and building.name then
        table.insert(result, language_name_types[building.name.type] or '')
        if building.name.has_name then
            table.insert(result, dfhack.translation.translateName(building.name, true))
        end

        -- for temples and guildhalls, get assigned organization
        if df.abstract_building_templest:is_instance(building) then
            table.insert(result, get_location_religion(building.deity_data.Deity or building.deity_data.Religion, building.deity_type))
        elseif df.abstract_building_guildhallst:is_instance(building) then
            local dwarfified_profession = locationselector.get_profession_string(building.contents.profession)
            table.insert(result, dwarfified_profession)
        end

    end

    return table.concat(result, ' ')
end

local function get_stockpile_search_key(stockpile)
    local result = {}
    if #stockpile.name ~= 0 then table.insert(result, stockpile.name) end

    local flags = stockpile.settings.flags
    for flag, name in pairs(stockpile_settings_flag_names) do
        if flags[flag] then table.insert(result, name) end
    end

    table.insert(result, ('Stockpile #%s'):format(stockpile.stockpile_number))
    return table.concat(result, ' ')
end

local function get_workshop_search_key(workshop)
    local result = {}
    for _, unit_id in ipairs(workshop.profile.permitted_workers) do
        local unit = df.unit.find(unit_id)
        if unit then table.insert(result, sortoverlay.get_unit_search_key(unit)) end
    end

    table.insert(result, workshop.name)
    table.insert(result, df.workshop_type.attrs[workshop.type].name or '')
    table.insert(result, df.workshop_type[workshop.type])

    return table.concat(result, ' ')
end

local function get_farmplot_search_key(farmplot)
    local result = {}

    if #farmplot.name ~= 0 then table.insert(result, farmplot.name) else table.insert(result, 'Farm Plot') end

    local plant = df.plant_raw.find(farmplot.plant_id[farmplot.last_season])
    if plant then table.insert(result, plant.name_plural) end

    return table.concat(result, ' ')
end

-- ----------------------
-- PlacesOverlay
--

PlacesOverlay = defclass(PlacesOverlay, sortoverlay.SortOverlay)
PlacesOverlay.ATTRS{
    desc='Adds search functionality to the places overview screens.',
    default_pos={x=71, y=9},
    viewscreens='dwarfmode/Info',
    frame={w=40, h=6}
}

function PlacesOverlay:init()
    self:addviews{
        widgets.BannerPanel{
            view_id='panel',
            frame={l=0, t=0, r=0, h=1},
            visible=self:callback('get_key'),
            subviews={
                widgets.EditField{
                    view_id='search',
                    frame={l=1, t=0, r=1},
                    label_text="Search: ",
                    key='CUSTOM_ALT_S',
                    on_change=function(text) self:do_search(text) end,
                },
            },
        },
    }

    self:register_handler('ZONES', buildings.list[df.buildings_mode_type.ZONES], curry(sortoverlay.single_vector_search, {get_search_key_fn=get_zone_search_key}))
    self:register_handler('LOCATIONS', buildings.list[df.buildings_mode_type.LOCATIONS], curry(sortoverlay.single_vector_search, {get_search_key_fn=get_location_search_key}))
    self:register_handler('STOCKPILES', buildings.list[df.buildings_mode_type.STOCKPILES], curry(sortoverlay.single_vector_search, {get_search_key_fn=get_stockpile_search_key}))
    self:register_handler('WORKSHOPS', buildings.list[df.buildings_mode_type.WORKSHOPS], curry(sortoverlay.single_vector_search, {get_search_key_fn=get_workshop_search_key}))
    self:register_handler('FARMPLOTS', buildings.list[df.buildings_mode_type.FARMPLOTS], curry(sortoverlay.single_vector_search, {get_search_key_fn=get_farmplot_search_key}))
end

function PlacesOverlay:get_key()
    if info.current_mode == df.info_interface_mode_type.BUILDINGS then
        return df.buildings_mode_type[buildings.mode]
    end
end

function PlacesOverlay:updateFrames()
    local ret = info_overlay.resize_overlay(self)
    local l, t = info_overlay.get_panel_offsets()
    local frame = self.subviews.panel.frame
    if frame.l == l and frame.t == t then return ret end
    frame.l, frame.t = l, t
    return true
end

function PlacesOverlay:onRenderBody(dc)
    PlacesOverlay.super.onRenderBody(self, dc)
    if self:updateFrames() then
        self:updateLayout()
    end
end

return _ENV
