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

student_data = serialize.define({
    {"room", "i16"},
    {"sit", "bool"},
    {"using", "u14"}
})

local common = require 'room.common'
encode_tooltip = common.encode_tooltip_def
decode_tooltip = common.decode_tooltip_def

function update(room)
    local objects = room.objects
    local num_toilets = 0
    for _, c in ipairs(objects) do
        if c.key == "base:toilet/stall" then
            num_toilets = num_toilets + 1
        end
    end
    room.capacity = num_toilets
    room.properties.is_toilet = true
end

function save(room)
    local objects = room.objects
    local o_data = {}
    for idx, e in ipairs(objects) do
        if e.key == "base:toilet/stall" then
            local owned = e.properties['owned']
            if owned ~= nil and not owned.valid then
                owned = nil
            end
            local sid = nil
            if e.properties['owned'] ~= nil then
                sid = e.properties['owned'].id
            end
            o_data[idx] = {
                owned = sid,
            }
        else
            o_data[idx] = {}
        end
    end

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

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

    for idx, e in ipairs(objects) do
        if e.key == "base:toilet/stall" then
            if data.objects[idx].owned ~= nil then
                e.properties['owned'] = get_entity_by_id(data.objects[idx].owned)
            end
        end
    end
end

function force_entity_release(room, e)
end

function server(room)
    local visitors = room.properties.users or {}
    local objects = room.objects

    plants.tick_plants(room)
    for _, e in ipairs(room.visitors) do
        e:release()
    end

    for _, e in ipairs(room.owned) do
        e:force_release()
    end


    local rx, ry = room:get_position()
    for _, e in ipairs(visitors) do
        local data = e.properties['data'] or {using = 0}
        data.room = room.room_id
        if e.properties.do_release then
            local stall = e.properties['stall']
            if stall ~= nil then
                stall.properties['owned'] = nil
            end
            if sit.try_stand(e, data) then
                e.properties.release = true
            else
                e.state = student_data.encode(data)
            end
        else
            if not e.is_walking then
                local stall = e.properties['stall']
                if stall == nil then
                    util.table_shuffle(objects)
                    for _, c in ipairs(objects) do
                        local owned = c.properties['owned']
                        if (owned == nil or not owned.valid) and c.key == "base:toilet/stall" then
                            stall = c
                            break
                        end
                    end
                end
                if stall ~= nil then
                    local x, y = e:get_position()
                    local stall_e = stall.entities[1]
                    local cx, cy = stall_e:get_position()
                    stall.properties['owned'] = e
                    e.properties['stall'] = stall
                    local rotation = stall_e.rotation
                    cx = cx + 0.15 * math.sin(rotation)
                    cy = cy + 0.15 * math.cos(rotation)
                    data.using = room:object_index(stall) + 1
                    if math.abs(x - (rx + cx)) > 0.05 or math.abs(y - (ry + cy)) > 0.05 then
                        e.properties['sit_time'] = math.random(20 * 4, 20 * 10)
                        e:walk_to_face(rx + cx, ry + cy, rotation)
                    else
                        e.properties['sit_time'] = (e.properties['sit_time'] or 0) - 1
                        if e.properties['sit_time'] <= 0 then
                            data.using = 0
                            if sit.try_stand(e, data) then
                                e:change_stat("happiness", 0.25)
                                e.properties.do_release = true
                            else
                                e.state = student_data.encode(data)
                            end
                        else
                            sit.make_sit(e, data)
                            e.state = student_data.encode(data)
                        end
                    end
                end
            end
        end
    end

end

function client(room, entities)
    local rx, ry = room:get_position()
    local objects = room.objects

    for idx, o in ipairs(objects) do
        if o.key == "base:toilet/stall" then
            local student = o.properties['user']
            if student ~= nil and not student.valid then
                student = nil
                o.properties['user'] = nil
            end
            local o_e = o.entities[1]
            local ox, oy = o_e:get_position()

            local should_close = false
            if student ~= nil then
                should_close = student.properties['sitting']
                    or student.properties['using'] == idx + 1
                    or false
            end

            local closed = o.properties['closed'] or false
            if closed and not should_close then
                o_e:play_animation("opening")
                audio.play_sound_at("door_open", rx + ox, ry + oy)
                o.properties['closed'] = false
            elseif not closed and should_close then
                o_e:play_animation("closing")
                o.properties['closed'] = true
            end
        end
    end
    plants.tick_plants_client(room)
end

function client_idle(room, e)
    local rx, ry = room:get_position()
    local objects = room.objects

    if e.state ~= nil then
        local data = student_data.decode(e.state)
        sit.client_sit_tick(e, data)
        if data.sit then
            -- If the student is sitting then find the stall
            -- they are using and close the door
            local o = objects[data.using - 1]
            local closed = o.properties['closed'] or false
            o.properties['user'] = e
            e.properties['using'] = data.using
            if not closed then
                local o_e = o.entities[1]
                o_e:play_animation("closing")
                o.properties['closed'] = true
            end
        end
    end
end

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