BaseView = {}

----------------------------------------------------------------------

function BaseView:init(definition)
    -- build view based on definition
    self.objects = {}
    self.shortcuts = {}
    
    local def = definition or self.definition
    if type(def) == "string" then
        def = file_load_lua_table("layouts/"..def..".lua")
    end
    
    for k,v in pairs(def) do
        self:create_and_add_object(v, false)
    end
    self:sort_objects()
end


function BaseView:create_and_add_object(definition, sort_afterwards)
    local o = copy_table(_G[definition.type])
    assert(o)
    o:init(definition, self)
    self:add_object(o, sort_afterwards)
    if definition.shortcut then
        self.shortcuts[definition.shortcut] = o
    end
    return o
end


function BaseView:add_object(object, sort_afterwards)
    -- note: sort_afterwards is true by default, force skip by passing false
    table.insert(self.objects, object)
    if sort_afterwards == true or sort_afterwards == nil then
        self:sort_objects()
    end
end


function BaseView:sort_objects()
    table.sort(self.objects, function(a,b) return a.z < b.z end)
end


function BaseView:destroy()
    -- destroy all child objects
    if self.objects then
        for i,o in ipairs(self.objects) do
            if o.destroy then o:destroy() end
        end
    end
    self.objects = nil
    self:destroy_prerendered_view()
    log("Destroyed view")
end


function BaseView:destroy_parent()
    if self.parent_view then
        self.parent_view:destroy_parent()
        self.parent_view:destroy()
        self.parent_view = nil
    end
end


function BaseView:update(dt)
    local o
    local handled = false

    -- handle clicks and mouse overs
    for i = #self.objects, 1, -1 do
        o = self.objects[i]

        if o.enabled and o.area then
            if not handled and o:point_inside(mouse.x, mouse.y) then
                if not o.mouse_over then
                    o.mouse_over = true
                    if o.mouse_in then o:mouse_in() end
                end

                if mouse.left_down and o.mouse_left_down then
                    o:mouse_left_down()
                end

                if mouse.right_down and o.mouse_right_down then
                    o:mouse_right_down()
                end

                if mouse.left_click then
                    if o.mouse_left_click then o:mouse_left_click() end
                    if o.call_mouse_click then o.call_mouse_click(self, o) end
                end
                
                if mouse.right_click then
                    if o.mouse_right_click then o:mouse_right_click() end
                end

                handled = true
            else
                if o.mouse_over then
                    o.mouse_over = false
                    if o.mouse_out then o:mouse_out() end
                end
            end
        end
    end

    -- update objects
    for i,o in ipairs(self.objects) do
        if o.update and o.enabled then
            o:update(dt)
        end
    end
    
    self:prune_objects()
end


function BaseView:render()
    local areas = dev_mode and kbd_down("f5")
    
    for i,o in ipairs(self.objects) do
        if o.render and o.enabled then
            o:render()
        end
        if areas and o.area and o.enabled then
            o:render_area_box()
        end
    end
end


function BaseView:prune_objects()
    -- destroy marked objects
    local o
    for i = #self.objects, 1, -1 do
        if self.objects[i].to_destroy then
            o = self.objects[i]
            if o.shortcut then
                self.shortcuts[o.shortcut] = nil
            end
            o:destroy()
            table.remove(self.objects, i)
        end
    end
end


function BaseView:close()

end


function BaseView:close_parent()

end


function BaseView:render_to_texture() -- with_alpha
    local render_target = gfx_create_bitmap(800, 600, true)
    if render_target then
        gfx_render_target(render_target)--, "000000", 1)
        gfx_blending("max", false, false, false, true)
        self:render()
        gfx_blending("normal", true, true, true, false)
        self:render()
        gfx_blending("normal", true, true, true, true)
        gfx_render_target(nil)
    end
    return render_target
end


function BaseView:prerender_view()
    self:destroy_prerendered_view()
    self.prerendered_view = self:render_to_texture()
    log("Prerendered view: create")
    return self.prerendered_view
end


function BaseView:destroy_prerendered_view()
    if self.prerendered_view then
        log("Prerendered view: destroy")
        gfx_release_bitmap(self.prerendered_view)
        self.prerendered_view = nil
    end
end



----------------------------------------------------------------------

function create_view(class, options)
    log("Creating view: "..tostring(class.definition))
    local x = copy_table(class)
    x:init(options)
    log("Creating view ended")
    timer_catchup()
    return x
end
