--
-- Facility Overview App
--

local util          = require("scada-common.util")

local iocontrol     = require("pocket.iocontrol")
local pocket        = require("pocket.pocket")

local style         = require("pocket.ui.style")

local dyn_tank      = require("pocket.ui.pages.dynamic_tank")
local facility_sps  = require("pocket.ui.pages.facility_sps")
local induction_mtx = require("pocket.ui.pages.facility_matrix")

local core          = require("graphics.core")

local Div           = require("graphics.elements.Div")
local MultiPane     = require("graphics.elements.MultiPane")
local TextBox       = require("graphics.elements.TextBox")

local WaitingAnim   = require("graphics.elements.animations.Waiting")

local DataIndicator = require("graphics.elements.indicators.DataIndicator")
local IconIndicator = require("graphics.elements.indicators.IconIndicator")

local ALIGN = core.ALIGN
local cpair = core.cpair

local APP_ID = pocket.APP_ID

local label_fg_bg  = style.label
local lu_col       = style.label_unit_pair

local basic_states = style.icon_states.basic_states
local mode_states  = style.icon_states.mode_states
local red_ind_s    = style.icon_states.red_ind_s
local yel_ind_s    = style.icon_states.yel_ind_s
local grn_ind_s    = style.icon_states.grn_ind_s

-- new unit page view
---@param root Container parent
local function new_view(root)
    local db = iocontrol.get_db()

    local frame = Div{parent=root,x=1,y=1}

    local app = db.nav.register_app(APP_ID.FACILITY, frame, nil, false, true)

    local load_div = Div{parent=frame,x=1,y=1}
    local main = Div{parent=frame,x=1,y=1}

    TextBox{parent=load_div,y=12,text="Loading...",alignment=ALIGN.CENTER}
    WaitingAnim{parent=load_div,x=math.floor(main.get_width()/2)-1,y=8,fg_bg=cpair(colors.orange,colors._INHERIT)}

    local load_pane = MultiPane{parent=main,x=1,y=1,panes={load_div,main}}

    app.set_sidebar({ { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home } })

    local tank_page_navs = {}
    local page_div = nil ---@type Div|nil

    -- load the app (create the elements)
    local function load()
        local fac  = db.facility
        local f_ps = fac.ps

        page_div = Div{parent=main,y=2,width=main.get_width()}

        local panes = {} ---@type Div[]

        -- refresh data callback, every 500ms it will re-send the query
        local last_update = 0
        local function update()
            if util.time_ms() - last_update >= 500 then
                db.api.get_fac()
                last_update = util.time_ms()
            end
        end

        --#region facility overview

        local main_pane = Div{parent=page_div}
        local f_div = Div{parent=main_pane,x=2,width=main.get_width()-2}
        table.insert(panes, main_pane)

        local fac_page = app.new_page(nil, #panes)
        fac_page.tasks = { update }

        TextBox{parent=f_div,y=1,text="Facility",alignment=ALIGN.CENTER}

        local mtx_state = IconIndicator{parent=f_div,y=3,label="Matrix Status",states=basic_states}
        local sps_state = IconIndicator{parent=f_div,label="SPS Status",states=basic_states}
        mtx_state.register(fac.induction_ps_tbl[1], "InductionMatrixStatus", mtx_state.update)
        sps_state.register(fac.sps_ps_tbl[1], "SPSStatus", sps_state.update)

        TextBox{parent=f_div,y=6,text="RTU Gateways",fg_bg=label_fg_bg}
        local rtu_count = DataIndicator{parent=f_div,x=19,y=6,label="",format="%3d",value=0,lu_colors=lu_col,width=3}
        rtu_count.register(f_ps, "rtu_count", rtu_count.update)

        TextBox{parent=f_div,y=8,text="Induction Matrix",alignment=ALIGN.CENTER}

        local eta = TextBox{parent=f_div,x=1,y=10,text="ETA Unknown",alignment=ALIGN.CENTER,fg_bg=cpair(colors.white,colors.gray)}
        eta.register(fac.induction_ps_tbl[1], "eta_string", eta.set_value)

        TextBox{parent=f_div,y=12,text="Unit Statuses",alignment=ALIGN.CENTER}

        f_div.line_break()

        for i = 1, fac.num_units do
            local ctrl = IconIndicator{parent=f_div,label="U"..i.." Control State",states=mode_states}
            ctrl.register(db.units[i].unit_ps, "U_ControlStatus", ctrl.update)
        end

        --#endregion

        --#region facility annunciator

        local a_pane = Div{parent=page_div}
        local a_div = Div{parent=a_pane,x=2,width=main.get_width()-2}
        table.insert(panes, a_pane)

        local annunc_page = app.new_page(nil, #panes)
        annunc_page.tasks = { update }

        TextBox{parent=a_div,y=1,text="Annunciator",alignment=ALIGN.CENTER}

        local all_ok  = IconIndicator{parent=a_div,y=3,label="Units Online",states=grn_ind_s}
        local ind_mat = IconIndicator{parent=a_div,label="Induction Matrix",states=grn_ind_s}
        local sps     = IconIndicator{parent=a_div,label="SPS Connected",states=grn_ind_s}

        all_ok.register(f_ps, "all_sys_ok", all_ok.update)
        ind_mat.register(fac.induction_ps_tbl[1], "InductionMatrixStateStatus", function (status) ind_mat.update(status > 1) end)
        sps.register(fac.sps_ps_tbl[1], "SPSStateStatus", function (status) sps.update(status > 1) end)

        a_div.line_break()

        local auto_scram  = IconIndicator{parent=a_div,label="Automatic SCRAM",states=red_ind_s}
        local matrix_flt  = IconIndicator{parent=a_div,label="Ind. Matrix Fault",states=yel_ind_s}
        local matrix_fill = IconIndicator{parent=a_div,label="Matrix Charge Hi",states=red_ind_s}
        local unit_crit   = IconIndicator{parent=a_div,label="Unit Crit. Alarm",states=red_ind_s}
        local fac_rad_h   = IconIndicator{parent=a_div,label="FAC Radiation Hi",states=red_ind_s}
        local gen_fault   = IconIndicator{parent=a_div,label="Gen Control Fault",states=yel_ind_s}

        auto_scram.register(f_ps, "auto_scram", auto_scram.update)
        matrix_flt.register(f_ps, "as_matrix_fault", matrix_flt.update)
        matrix_fill.register(f_ps, "as_matrix_fill", matrix_fill.update)
        unit_crit.register(f_ps, "as_crit_alarm", unit_crit.update)
        fac_rad_h.register(f_ps, "as_radiation", fac_rad_h.update)
        gen_fault.register(f_ps, "as_gen_fault", gen_fault.update)

        --#endregion

        --#region induction matrix

        local mtx_page_nav = induction_mtx(app, panes, Div{parent=page_div}, fac.induction_ps_tbl[1], update)

        --#endregion

        --#region SPS

        local sps_page_nav = facility_sps(app, panes, Div{parent=page_div}, fac.sps_ps_tbl[1], update)

        --#endregion

        --#region facility tank pages

        local t_pane = Div{parent=page_div}
        local t_div = Div{parent=t_pane,x=2,width=main.get_width()-2}
        table.insert(panes, t_pane)

        local tank_page = app.new_page(nil, #panes)
        tank_page.tasks = { update }

        TextBox{parent=t_div,y=1,text="Facility Tanks",alignment=ALIGN.CENTER}

        local f_tank_id = 1
        for t = 1, #fac.tank_list do
            if fac.tank_list[t] == 1 then
                t_div.line_break()

                local tank = IconIndicator{parent=t_div,x=1,label="Unit Tank "..t.." (U-"..t..")",states=basic_states}
                tank.register(db.units[t].tank_ps_tbl[1], "DynamicTankStatus", tank.update)

                TextBox{parent=t_div,x=5,text="\x07 Unit "..t,fg_bg=label_fg_bg}
            elseif fac.tank_list[t] == 2 then
                tank_page_navs[f_tank_id] = dyn_tank(app, nil, panes, Div{parent=page_div}, t, fac.tank_ps_tbl[f_tank_id], update)

                t_div.line_break()

                local tank = IconIndicator{parent=t_div,x=1,label="Fac. Tank "..f_tank_id.." (F-"..f_tank_id..")",states=basic_states}
                tank.register(fac.tank_ps_tbl[f_tank_id], "DynamicTankStatus", tank.update)

                local connections = ""
                for i = 1, #fac.tank_conns do
                    if fac.tank_conns[i] == t then
                        if connections ~= "" then
                            connections = connections .. "\n\x07 Unit " .. i
                        else
                            connections = "\x07 Unit " .. i
                        end
                    end
                end

                TextBox{parent=t_div,x=5,text=connections,fg_bg=label_fg_bg}

                f_tank_id = f_tank_id + 1
            end
        end

        --#endregion

        -- setup multipane
        local f_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes}
        app.set_root_pane(f_pane)

        -- setup sidebar

        local list = {
            { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home },
            { label = "FAC", tall = true, color = core.cpair(colors.black, colors.orange), callback = fac_page.nav_to },
            { label = "ANN", color = core.cpair(colors.black, colors.yellow), callback = annunc_page.nav_to },
            { label = "MTX", color = core.cpair(colors.black, colors.white), callback = mtx_page_nav },
            { label = "SPS", color = core.cpair(colors.black, colors.purple), callback = sps_page_nav },
            { label = "TNK", tall = true, color = core.cpair(colors.black, colors.blue), callback = tank_page.nav_to }
        }

        for i = 1, #fac.tank_data_tbl do
            table.insert(list, { label = "F-" .. i, color = core.cpair(colors.black, colors.lightGray), callback = tank_page_navs[i] })
        end

        app.set_sidebar(list)

        -- done, show the app
        load_pane.set_value(2)
    end

    -- delete the elements and switch back to the loading screen
    local function unload()
        if page_div then
            page_div.delete()
            page_div = nil
        end

        app.set_sidebar({ { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home } })
        app.delete_pages()

        -- show loading screen
        load_pane.set_value(1)
    end

    app.set_load(load)
    app.set_unload(unload)

    return main
end

return new_view
