<?php

namespace loyalsoft;

// <editor-fold defaultstate="collapsed" desc="    定义   ">

/**
 *   约定好的消息类型
 */
class SysMessageType extends Enum {

    /**  (1)XXX（玩家名称）解锁英雄XXX（紫色橙色英雄）  */
    const GetHero = 1;

    /** (2)XXX（玩家名称）的英雄XXX（紫色橙色英雄）神血升值40%+（40%都有） */
    const Hero_purification = 2;

    /** (3)XXX 获得XXX（紫色橙色装备） */
    const GetEquip = 3;

    /** (4)XXX（玩家名称）购买公会钻石礼包 */
    const BuyGuild_CashPack = 4;

    /** (5)XXX（玩家名称）升到XX级别(20级以上) */
    const UserLevelUp = 5;

    /** (6)XXX（玩家名称）达到XX段位(黄金以上) */
    const PVP_League = 6;

    /** (7) XXX（玩家名称）打败噩梦关八岐大蛇，获得铂金宝箱，可喜可贺！
     *  通过副本
     *  */
    const Pass_carbon = 7;

    /** (4)装备-强化  */
    const Weapon_Promote = 4000;

    /**
     * (99)玩家自己购买的全服消息(本分区)
     */
    const UserSendMessage = 99;

}

/**
 * 系统消息对象
 */
class SysMessageModel extends Object_ext {

    /** @var SysMessageType */
    public $type;

    /** @var array 消息数据 */
    public $datas;

    /** @var int */
    public $ts;

}

//
// </editor-fold>

/**
 * 系统消息逻辑处理流程
 * @author gwang
 */
class SystemProc {

    /**
     * 系统消息的过期时间(秒)
     * @var int
     */
    const SYS_MSG_OUTTS = 3600;

    /**
     * 主逻辑分发
     * @param type $req
     * @return type
     */
    static function procMain($req) {
        switch (req()->cmd) {
            case CmdCode::cmd_system_userSendsysmessage:                        # 6904 玩家发送系统广播
                return self::userPushSysMessage();
            case CmdCode::cmd_system_getsysmessage:                             # 6901 拉取系统消息
                return self::getSysMessage();
            case CmdCode::cmd_system_logreport:                                 # 6902 客户端上报日志
                return self::logReport();
            case CmdCode::cmd_system_clienttick:                                # 6903 客户端心跳包 
                return self::clientTick();
            default :
                return Resp::err(ErrCode::cmd_err);
        }
    }

//
// <editor-fold defaultstate="collapsed" desc=" 暂时不管 ">
//

    /**
     * [6903] 客户端心跳包 
     */
    static function clientTick() {
        $timespan = now() - ctx()->base()->lastSaveTs;
        if ($timespan < 300) {                                                  # 间隔超过5分钟的不算
            if ($timespan < 30) {                                               # 心跳包固定30秒1次
                $timespan = 30;
            }
            ctx()->privateData()->onlineGiftts += $timespan;
            UserProc::updateUserInfo();
        }
        return Resp::ok();
    }

    /**
     * [6902] 客户端日志上报 
     */
    static function logReport() {
        $max = 300;
        $once = 30;
        $key = "report-log";
        $log = req()->paras[0];                                                 # 客户端参数解析: 本地日志
        $logItem = array(#                                                      # 组装对象
            'uid' => req()->uid,
            'log' => $log,
            'ts' => TimeUtil::dtCurrent()
        );
        gMem()->lpush($key, array($logItem));                                   # 推送日志
        if (gMem()->llen($key) > $max + $once) {                                # 达到清理条件
            gMem()->ltrim($key, 0, -$once);                                     # 缩减记录
        }
        return Resp::ok("copy!");
    }

//
//
// </editor-fold>
//

    /**
     * 玩家通过xx副本消息
     * @param type $zoneid
     * @param Data_UserGame $user
     * @param int $carbonID
     *      */
    static function Carbon_Win($zoneid, $user, $carbonID, $hardLevel) {
        if (512001 == $carbonID) {
            self::pushSysMessage($zoneid, SysMessageType::Pass_carbon, array(
                $user->name, $carbonID, $hardLevel
            ));
        }
    }

    /**
     * 玩家pvp段位消息
     * @param type $zoneid
     * @param Data_UserGame $user
     * @param int $leagueID
     *      */
    static function PVP_league($zoneid, $user, $leagueID) {
        if ($leagueID > 10) {
            self::pushSysMessage($zoneid, SysMessageType::PVP_League, array(
                $user->name, GameConfig::pvp_leaguescore_getItem($leagueID)->leagueName
            ));
        }
    }

    /**
     * [6901]获取系统广播消息列表 
     */
    static function getSysMessage() {
        //客户端参数解析
        $ts = req()->paras[0];                                                   # 消息列表有效时间戳
        $defaultwaitcont = 60;                                                  # 暂时使用60秒作为频率,若是有压力就调大些. 若是没有问题,可以调小些.
        $itemDisplayTime = 7;                                                   # 7秒显示完一条消息

        $sysMessage = self::mem_getSysMsg_zset(req()->zoneid, $ts);

        $count = count($sysMessage) * $itemDisplayTime;                         # 计算下次取消息的时间
        if ($count < $defaultwaitcont) {                                        # 最低刷新时间
            $count = $defaultwaitcont;
        }
        $ret = array(
            'sysMessage' => $sysMessage,
            'nextFetchTime' => $count
        );

        return Resp::ok($ret);                                                  # 返回信息
    }

    /**
     * [6904]玩家发送系统广播消息 
     */
    static function userPushSysMessage() {
        list($msg, $type) = req()->paras;                                        # 提取参数: 消息内容, 消耗道具类型,1:钻石,2:xx
        $uid = req()->uid;
        $user = req()->userInfo->game;
        $cost = 0;                                                              // 花费
        switch ($type) {
            case 1:                                                             # 钻石
                $cost = glc()->SystemMessage_UserSendToMyZone_Cost;
                my_Assert($cost, ErrCode::err_msg_usersnedmsg_errorcost);
                my_Assert($user->base()->Consume_Cash($cost), ErrCode::notenough_cash_msg);
                break;
            default :
                Err(ErrCode::paras_err);                                        // 其他类型:参数非法
        }
        self::pushSysMessage(req()->zoneid, #
                SysMessageType::UserSendMessage, array($uid, $user->name, $msg));
        UserProc::updateUserInfo();                                             // 回存账号数据
        return Resp::ok(array('ret' => "succeed"));                             # 返回值
    }

    // -----------------辅助方法---------------------
    //

    /**
     * 玩家升级消息
     * @param type $zoneid
     * @param Data_UserGame $user
     * @param int $newLevel
     *      */
    static function UserLevelUp($zoneid, $user, $newLevel) {
        if ($newLevel > 20) {
            self::pushSysMessage($zoneid, SysMessageType::UserLevelUp, array(
                $user->name, $newLevel
            ));
        }
    }

    /**
     * 插入英雄升阶消息
     * @param int $zoneid
     * @param string $uid
     * @param string $name
     * @param string $heroname
     * @param int $level
     */
    static function insertHero_StageUp($zoneid, $uid, $name, $heroname, $level) {
//        if ($level >= glc()->SystemMessage_HeroStage_Limit_Min) {
//            self::pushSysMessage($zoneid, SysMessageType::GetEquip, array(
//                $uid, $name, $heroname, $level
//            ));
//        }
    }

    /**
     * 添加购买公会钻石礼包消息
     * @param type $zoneid
     * @param Data_UserGame $user
     * */
    static function BuyGuildCashPack($zoneid, $user) {
        self::pushSysMessage($zoneid, SysMessageType::BuyGuild_CashPack, array(
            $user->name
        ));
    }

    /**
     * 添加获得装备消息
     * @param type $zoneid
     * @param Data_UserGame $user
     * @param int $equipModelId
     * @deprecated since version 0 待维修 --王刚2020年1月2日21:07:04
     *      */
    static function GetEquip($zoneid, $user, $equipModelId) {
        $equipModel = GameConfig::item_getItem($equipModelId);
        if ($equipModel && $equipModel->quailty > 3) {                          # 紫色橙色装备
            self::pushSysMessage($zoneid, SysMessageType::GetEquip, array(
                $user->name, $equipModel->name
            ));
        }
    }

    /**
     * 插入装备强化消息
     * @deprecated since version 1.0 装备强化暂不支持了
     * @param type $zoneid
     * @param type $uid
     * @param type $name
     * @param type $weaponname
     * @param type $level
     */
    static function insertWeapon_promoteUp($zoneid, $uid, $name, $weaponname, $level) {
//        if ($level >= glc()->SystemMessage_WeaponLevel_Limit_Min) {
//            self::pushSysMessage($zoneid, SysMessageType::Weapon_Promote, array(
//                $uid, $name, $weaponname, $level
//            ));
//        }
    }

////=================////

    /**
     * 添加获得英雄消息
     * @param type $zoneid
     * @param Data_UserGame $user
     * @param int $heroId
     * @return int $err
     *      */
    static function GetHero($zoneid, $user, $heroId) {
        $heroModel = GameConfig::hero_getItem($heroId);
        if ($heroModel && $heroModel->zhenxidu > 3) {
            self::pushSysMessage($zoneid, SysMessageType::GetHero, array(
                $user->name, $heroModel->name
            ));
        }
    }

    /**
     * 添加英雄血脉提纯消息
     * @param type $zoneid
     * @param Data_UserGame $user
     * @param int $heroId
     * @return int $err
     *      */
    static function Hero_purification($zoneid, $user, $heroId) {
        $heroModel = GameConfig::hero_getItem($heroId);
        if ($heroModel && $heroModel->zhenxidu > 3) {
            self::pushSysMessage($zoneid, SysMessageType::Hero_purification, array(
                $user->name, $heroModel->name
            ));
        }
    }

//
// <editor-fold defaultstate="collapsed" desc="    读写memdb   ">

    /**
     * 取数据
     * @param int $zoneid
     * @return array
     */
    private static function mem_getSysMsg_zset($zoneid, $ts) {
        $ret = gMem()->zrangebyscore(MemKey_GameRun::Game_SysMsgByZone_zset($zoneid), $ts, now(+1));
        //todo:目前是在这里手动解码的, 应该移动到CRedisUtil里面去.
        $arr = ArrayInit();
        if ($ret) {
            foreach ($ret as $msg) {
                $arr[] = JsonUtil::decode($msg);
            }
        }
        return $arr;
    }

    /**
     * 回写数据
     * @param int $zoneid
     * @param SysMessageModel $value
     */
    private static function mem_addSysMsg_zset($zoneid, $value) {
        $ts = $value->ts;
        $key = MemKey_GameRun::Game_SysMsgByZone_zset($zoneid);
        gMem()->zadd($key, array(json_encode($value) => $ts));                  # 插入消息
        gMem()->zremrangebyscore($key, 0, $ts - self::SYS_MSG_OUTTS);           # 清理过期数据
    }

// </editor-fold>
//

    /**
     * 推送系统消息
     * @param int $zoneid 分区
     * @param SysMessageType $type enum
     * @param array $datas
     */
    static function pushSysMessage($zoneid, $type, $datas) {
        $newMsg = new SysMessageModel(array(#                                   # 添加新系统消息
            'type' => $type,
            'datas' => $datas,
            'ts' => now()
        ));
        self::mem_addSysMsg_zset($zoneid, $newMsg);                             # 写入mem
    }

// <editor-fold defaultstate="collapsed" desc=" 备用 需修改">

    /**
     * 添加中奖消息
     * @param type $mem
     * @param UserModel $user
     * @param int $itemId
     * @param string $src 来源: 砸木桶,砸金蛋,公会抽奖,开宝箱,蛋蛋忧伤,...
     * @return int $err
     *      */
    static function insertLotterySysMessage($zoneid, $mem, $user, $itemId, $src) {
        throw new \Exception("need reimplement");
        $err = ErrCode::ok;
// 向系统消息区域发送中奖消息.

        $broadCastIDs = glc()->broadCastIDs;
        if ($broadCastIDs == null) {                                            # 需要广播的道具ID
            $err = ErrCode::err_msg_buildrewardnoconst;
        } else {
            $broadItemArray = JsonUtil::decode($broadCastIDs->content);
            if (!GAME_ONLINE || CommUtil::isPropertyExists($broadItemArray, $itemId)) {# 如果是测试的话,将所有中奖物品加入到系统消息中
                self::pushSysMessage($zoneid, SysMessageType::GetHero, #
                        array($user->oid, $user->name, $itemId, $src));
            }
        }
        return $err;
    }

// </editor-fold>
}
