
local common = require 'room.common'
local plants = require 'objects.plants'
local util = require 'util'

local student_data = serialize.define({
    {"using_items", "bool"}
})

encode_tooltip = common.encode_tooltip
decode_tooltip = common.decode_tooltip

function update(room)
    local objects = room.objects
    local num_desks = 0
    for _, c in ipairs(objects) do
        if c.key == "base:teach_objs/science_desk" then
            num_desks = num_desks + 1
        end
    end
    room.capacity = num_desks
    common.update(room)
end

function save(room)
    local visitors = room.visitors
    local objects = room.objects

    local v_data = {}
    for _, e in ipairs(visitors) do
        v_data[e.id] = {
            desk = room:object_index(e.properties['desk']),
            common = common.save_student(e),
        }
    end

    local o_data = {}
    for idx, e in ipairs(objects) do
        if e.key == "base:teach_objs/science_desk" then
            o_data[idx] = {
                owned = e.properties['owned'],
            }
        else
            o_data[idx] = {}
        end
    end

    return {
        plants = plants.save_plants(room),
        visitors = v_data,
        objects = o_data,
    }
end

function load(room, data)
    plants.load_plants(room, data.plants)
    local visitors = room.visitors
    local objects = room.objects

    for _, e in ipairs(visitors) do
        local d = data.visitors[e.id]
        if d.desk ~= nil then
            e.properties['desk'] = objects[d.desk]
        end
        common.load_student(e, d.common)
    end

    for idx, e in ipairs(objects) do
        if e.key == "base:teach_objs/science_desk" then
            e.properties['owned'] = data.objects[idx].owned
        end
    end
end

force_entity_release = common.force_entity_release

function server(room)
    local visitors = room.visitors
    local objects = room.objects

    plants.tick_plants(room)

    -- Send students to stand at desks
    local num_active = 0
    for _, e in ipairs(visitors) do
        if e.should_release then
            local desk = e.properties['desk']
            if desk ~= nil then
                desk.properties['owned'] = false
            end
            -- TODO: Allow customizing
            common.release_student(room, e, 500, 1.2)
            e:release()
        else
            num_active = num_active + 1
            if not e.is_walking then
                local desk = e.properties['desk']
                if desk == nil then
                    util.table_shuffle(objects)
                    for _, c in ipairs(objects) do
                        if not c.properties['owned'] and c.key == "base:teach_objs/science_desk" then
                            desk = c
                            break
                        end
                    end
                end
                if desk ~= nil then
                    local x, y = e:get_position()
                    local desk_e = desk.entities[1]
                    local cx, cy = desk_e:get_position()
                    desk.properties['owned'] = true
                    e.properties['desk'] = desk
                    local rotation = desk_e.rotation
                    cx = cx + 0.12 * math.sin(rotation)
                    cy = cy + 0.12 * math.cos(rotation)
                    if math.abs(x - cx) > 0.05 or math.abs(y - cy) > 0.05 then
                        if e.properties.tried_walk ~= desk then
                            -- Try to sit on the target desk
                            e.properties.tried_walk = desk
                            e:walk_to_face(cx, cy, rotation)
                        else
                            -- We've failed to sit once, mark as stuck
                            e.properties.stuck = true
                        end
                    else
                        e.state = student_data.encode({
                            using_items = true
                        })
                        common.tick_student(room, e)
                    end
                end
            end
        end
    end

    local has_prof = false
    for i = #room.owned, 1, -1 do
        local e = room.owned[i]
        if e.key == 'base:professor' then
            if not has_prof then
                has_prof = true
            else
                e:force_release()
            end
        else
            e:force_release()
        end
    end

    common.tick_room(room, num_active > 0 or room.has_waiting)
end

if is_client then

    local beaker_matrix = new_matrix()
        :translate(-0.1, 0.3, -0.1)
        :rotate_z(-90)

    local vial_matrix = new_matrix()
        :translate(-0.1, 0.2, -0.1)
        :rotate_z(90)

    function client(room, entities)
        common.tick_staff_client(room, entities)
        for _, e in ipairs(entities) do
            if e.state ~= nil and e.key == "base:student" then
                local data = student_data.decode(e.state)
                if data.using_items and not e.properties['objects'] then
                    local beaker = e:add_attachment("base:science/beaker_green", "LeftHand", beaker_matrix)
                    local vial = e:add_attachment("base:science/vial_red", "RightHand", vial_matrix)
                    e.properties['objects'] = {
                        beaker = beaker,
                        vial = vial,
                    }
                end
                if data.using_items and e.animation ~= "play_beakers" then
                    e:play_animation("play_beakers")
                end
            end
        end
        plants.tick_plants_client(room)
    end
end

function on_exec(room, method, data)
    plants.on_exec(room, method, data)
end