-- mail.lua
-- 2018-05-20
-- xzc
-- 玩家邮件
--[[
个人邮件结构
{
    id:唯一id
    ctx:邮件内容
    title:标题
    attachment = -- 邮件附件，格式为通用奖励格式，也可以是背包道具，可包含强化、星级等...
    {
        { res = 1,id = 10001,count = 1},
        { res = 1,id = 10001,count = 1},
    }
}
]] local Module = require "modules.player.module"

local Mail = oo.class(..., Module)

function Mail:__init(pid, player)
    self.list = {}
    self.sys_id = 0

    self.modify = false
    self.db_query = string.format('{"_id":%d}', pid)
    Module.__init(self, pid, player)
end

-- 数据存库接口，自动调用
-- 必须返回操作结果
function Mail:db_save()
    if not self.modify then return true end

    -- 说明db里的数据比当前新，不能覆盖
    if self.reload then
        eprint("db_save find reload flag,data can NOT be overwrote")
        return false
    end

    local info = {sys_id = self.sys_id, list = self.list}
    g_mongodb:update("mail", self.db_query, info, true)
    return true
end

-- 数据加载接口，自动调用
-- 必须返回操作结果
function Mail:db_load(sync_db)
    local ecode, res = sync_db:find("mail", self.db_query)
    if 0 ~= ecode then return false end -- 出错

    if not res or not res[1] then return true end

    self.list = res[1].list
    -- 当玩家未创建mail时给他发了离线邮件就没有sys_id
    self.sys_id = res[1].sys_id or 0

    return true
end

-- 数据加载完成自动调用，用于初始化从数据库加载的数据
-- 必须返回操作结果
function Mail:on_init(is_new)
    local sys_id = g_mail_mgr:get_now_id()

    -- 新创建的号，直接跳过旧的全服邮件
    if is_new then
        self.sys_id = sys_id

        self.modify = true
        return self:db_save()
    end

    -- 检查是否有新全服邮件
    local new_cnt =
        g_mail_mgr:check_new_sys_mail(self.player, self, self.sys_id)
    if self.sys_id < sys_id then
        self.modify = true
        self.sys_id = sys_id
    end

    if new_cnt > 0 then self.modify = true end

    return true
end

-- 检查是否需要重新加载邮件
-- 防止正在登录的时候有人发了邮件
function Mail:check_reload()
    if not self.reload then return true end

    -- 不能直接改数据库又改了内存中的数据
    if self.modify then
        eprint("mail reload data modify found")
        return false
    end

    -- 重新读库
    if not self:db_load(self.player:get_sync_db()) then return false end

    -- 重新初始化数据
    return self:on_init(self.payer:is_new())
end

-- 玩家数据已加载完成，进入场景
-- 必须返回操作结果
function Mail:on_login()
    if not self:check_reload() then return false end

    self:send_info() -- 发送邮件数据
    return true
end

-- 玩家退出游戏
-- 必须返回操作结果，但这个结果不影响玩家数据存库
function Mail:on_logout()
    return true
end

-- 由mail_mgr添加一封邮件
function Mail:add_mail(mail)
    self.modify = true
    table.insert(self.list, mail)
    self:send_new_mail(mail)

    self:truncate()
end

-- 增加一封系统邮件
function Mail:add_sys_mail(mail)
    -- id是根据时间来算的，调时间有可能出现问题
    if self.sys_id >= mail.id then
        eprint("add_sys_mail sys id error:pid = %d,old = %d,now = %d", self.pid,
              self.sys_id, mail.id)
        return
    end
end

function Mail:raw_add_sys_mail(mail)
    if mail.id > self.sys_id then self.sys_id = mail.id end
    self:add_mail(mail)
end

-- 标识需要重新加载邮件(当你正在登录中，有收到新邮件)
function Mail:set_reload()
    self.reload = true
end

-- 删除多出的邮件
function Mail:truncate()
    -- TODO:策划应该会有删除要求，暂时不做
end

-- 发送邮件数据
function Mail:send_info()
    local pkt = {}
    pkt.mails = self.list

    self.player:send_pkt(MAIL.INFO, pkt)
end

-- 发送新邮件
function Mail:send_new_mail(new_mail)
    local pkt = {}
    pkt.mail = new_mail

    self.player:send_pkt(MAIL.NEW, pkt)
end

-- 能否删除邮件
function Mail:can_del(mail)
    return true
end

-- 处理邮件删除
function Mail:handle_mail_del(pkt)
    if not pkt.id or #pkt.id == 0 then
        return eprint("handle_mail_del no mail id specify:%d", self.pid)
    end

    local mail_map = {}
    for _, id in pairs(pkt.id) do mail_map[id] = true end

    -- 先判断所有邮件是否都可以删除
    for _, mail in pairs(self.list) do
        if mail_map[mail.id] then
            if not self:can_del(mail) then
                print("mail can not be delete", self.player.id, mail.id)
                return
            end
        end
    end

    -- 统一进行删除操作
    for id in pairs(mail_map) do
        for idx, mail in pairs(self.list) do
            if mail.id == id then
                table.remove(self.list, idx)
                Log.db_misc(self.player, LOG.DEL_MAIL, table.dump(mail))
                break
            end
        end
    end

    self.player:send_pkt(MAIL.DEL, pkt)
end

return Mail
