<?php

namespace loyalsoft;

require_once __DIR__ . '/ActiveProc/CipheredBase32.php';                        # 算法库

/**
 * 活动模块
 */
class ActiveProc {

    /**
     * 兑换码礼包使用记录
     */
    const tab_toke_gift = 'tab_token_gift';

    /**
     * 逻辑分发
     * 所有的Proc中必须有这样一个方法
     */
    public static function procMain() {
        switch (req()->cmd) {
            case CmdCode::active_levelgift_getReward:                           # 6501 等级奖励: 领取奖励
                return self::GetLevelGift();
            case CmdCode::active_day7_drawreward:                               # 6502 领取七日签到奖励
                return self::Day7_DrawReward();
            case CmdCode::active_getzonePublicTs:                               # 6503 查询开服时间戳
                return ActiveProc::GetZonePublicTS();
            case CmdCode::active_getTodayOnlineInfos:                           # 6504 查询当天在线时长
                return self::getTotayOnlineInfos();
            case CmdCode::Task_Tili:                                            # 6508 体力变化
                return ActiveProc::RecoveryTili();
            case CmdCode::active_token_drawReward:                              # 6512 兑换码礼包
                return self::drawActivePackageByCode();
            case CmdCode::active_draw_onlinegift:                               # 6513 领取在线(时长)礼包
                return self::drawOnlineGift();
            case CmdCode::active_draw_reggift:                                  # 6514 领取全服注册礼包
                return self::drawRegGift();
            case CmdCode::active_presentTili:                                   # 6515 领取在线赠送体力
                return self::drawTiliGift();
            case CmdCode::active_get_regnum:                                    # 6516 查询当前全服注册人数
                return self::getRegNumber();

            case CmdCode::active_BuyTili:                                       #6520 购买体力
                return self::BuyTili();
            case CmdCode::active_GetCurTili:                                    #6521 刷新体力
                return self::GetCurTili();
            case CmdCode::active_goldexchange:                                  #6522 金币兑换
                return self::Goldexchange();
            default:
                return Resp::err(ErrCode::cmd_err);
        }
    }

    /**
     * 6522  金币兑换
     * @return type
     */
    static function Goldexchange() {
        //$comList = req()->paras[0];

        $dic = GameConfig::goldexchange();
        $max = count((array) $dic);

        my_Assert(ctx()->base(true)->buyGoldNum < $max, ErrCode::active_goldExchangeNum_maxLimit);

        $mo = GameConfig::goldexchange_getItem(ctx()->base(true)->buyGoldNum + 1);
        my_Assert($mo != null, ErrCode::err_const_no);
        my_Assert(ctx()->base(true)->cash >= $mo->cashCostNum, ErrCode::notenough_cash_msg);

        ctx()->base(true)->buyGoldNum += 1;
        ctx()->base(true)->Consume_Cash($mo->cashCostNum);
        ctx()->base(true)->Add_Gold($mo->goldNum);

        UserProc::updateUserInfo();

        return Resp::ok(array("gold" => ctx()->base(true)->gold, "buyGoldNum" => ctx()->base(true)->buyGoldNum, "cash" => ctx()->base(true)->cash,));
    }

    static function ClearGoldExchangeNum() {
        ctx()->base(true)->buyGoldNum = 0;
    }

    /**
     * 每天重置
     */
    static function DailyReset() {
        self::DailyResetDay7Task();
        self::ClearOnlineGiftTs();
        self::ClearDailyTiliGift();
        self::ClearGoldExchangeNum();
    }

//
// <editor-fold defaultstate="collapsed" desc="    加油站: 领取体力    ">

    /**
     * [6515] 体力加油站 领取
     */
    static function drawTiliGift() {
        $user = ctx();
        list($giftId, $isLate) = req()->paras;                                  # 提取参数: 礼包id, 是否补领.

        $mo = GameConfig::activity_tiligift_getItem($giftId);
        my_Assert(null != $mo, ErrCode::err_const_no);                          # 配置数据
        my_Assert(!in_array($giftId, ctx()->privateData()->dailyDrawedTiliGift), ErrCode::active_hasgetted); # 已领取

        $now = date_create();                                                   # 当前
        $st = \date_create_from_format('H:i:s', $mo->start_time);               # 起始时间
        $ed = \date_create_from_format('H:i:s', $mo->end_time);                 # 结束时间

        $ok = false;                                                            # 逻辑是否通过
        if ($now > $st && $now < $ed) {                                         # 在时间段内,可以免费领
            $ok = true;
        } else if ($isLate) {                                                   # 如果是补领
            $ok = $user->base(true)->Consume_Cash($mo->late_cost);              # 扣除补领钻石后继续
            my_Assert($ok, ErrCode::notenough_cash_msg);                        # 钻石不足
        }
        my_Assert($ok, ErrCode::active_time);                                   # 时间段非法

        $user->base(true)->Add_tili($mo->tili);                                 # 加体力
        $user->privateData(true)->dailyDrawedTiliGift[] = $giftId;              # 记录

        UserProc::updateUserInfo();                                             # 回存
        #
//        $hour = date('G');
//        my_Assert(!in_array($hour, $privateState->dailyDrawedTiliGift), ErrCode::active_hasgetted); # 判断是否已领取
//        $arr = explode(',', glc()->activity_presentTili_times);                 # 判断是否满足领取条件
//        my_Assert(in_array($hour, $arr), ErrCode::active_illegal);              # 不满足条件
//        $base->Add_tili(glc()->activity_presentTili_number);                    # 增加体力
//        $privateState->dailyDrawedTiliGift[] = $hour;
//        UserProc::updateUserInfo();                                             # 回存

        return Resp::ok(array(#                                                 # 返回值
                    'record' => $user->privateData()->dailyDrawedTiliGift,
                    'cash' => $user->base()->cash,
                    'tili' => $user->base()->tili,
                    'TiliTime' => $user->privateState->TiliTime,
        ));
    }

////
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="    全服注册礼包    ">

    /**
     * [6516] 查询当前全服注册人数
     */
    static function getRegNumber() {
        return Resp::ok(array(
                    'num' => gMem()->get(MemKey_GameRun::Stat_UserCountByZone_int(req()->zoneid))
        ));
    }

    /**
     * [6514] 领取全服注册礼包
     */
    static function drawRegGift() {
        $user = new Data_UserGame(ctx());
        $privateState = new Info_PrivateState($user->privateState);
        $giftId = req()->paras[0];                                              # 礼包id
        $giftModel = GameConfig::activity_reggift_getItem($giftId);             # 取礼包常亮数据
        if (null == $giftModel) {
            return Resp::err(ErrCode::err_const_no);
        }
        if (in_array($giftId, $privateState->drawedRegGift)) {                  # 判断是否已领取
            return Resp::err(ErrCode::active_hasgetted);
        }
        // 判断是否满足领取条件
        if (gMem()->get(MemKey_GameRun::Stat_UserCountByZone_int(req()->zoneid)) < $giftModel->regNumber) {
            return Resp::err(ErrCode::active_illegal);                          # 不满足条件
        }
        $err = StoreProc::AddMultiItemInStore($giftModel->rewardstr);           # 发放奖励
        if ($err) {
            return Resp::err($err);                                             # 失败
        }
        $privateState->drawedRegGift[] = $giftId;
        $user->privateState = $privateState;
        ctx($user);
        UserProc::updateUserInfo();                                             # 回存
        return Resp::ok(array(#                                                 # 返回值
                    'key' => 'ok',
                    'store' => $user->store
        ));
    }

// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="    在线礼包   ">

    /**
     * 【6504】查询当天在线时长信息
     */
    static function getTotayOnlineInfos() {

        return Resp::ok(array(
                    "onlineGiftIDs" => ctx()->privateState->onlineGiftIDs,
                    "onlineGiftts" => ctx()->privateState->onlineGiftts
        ));
    }

    /**
     * [6513] 领取连续在线礼包
     */
    static function drawOnlineGift() {
        $giftid = req()->paras[0];                                              # 提取参数: 礼包的编号
        $user = ctx();
        $privateState = ctx()->privateData();
        $giftData = GameConfig::activity_onlinegift_getItem($giftid);           # 在线礼包常量数据
        my_Assert(null != $giftData, ErrCode::onlinegift_constno_err);          # 防御找不到配置数据
//        my_Assert($privateState->onlineGiftts + 30 >= $giftData->onlineSec, #        # 时间未到，不可以领取
//                ErrCode::onlinegift_timenotenough);

        my_default_Arr($privateState->onlineGiftIDs);                           # 防御未初始化领取记录
        my_Assert(!in_array($giftid, $privateState->onlineGiftIDs), #           # 判断礼包ID是否已经领取
                ErrCode::active_hasgetted);
        $err = StoreProc::AddMultiItemInStore($giftData->rewardstr);            # 发放奖励
        my_Assert(ErrCode::ok == $err, $err);                                   # 发放奖励失败
        $privateState->onlineGiftIDs[] = $giftid;                               # 记录已领礼包ID
        $privateState->onlineGiftts = 0;                                        #每次领取奖励则时间重新计算

        UserProc::updateUserInfo();                                             # 回写用户数据
        return Resp::ok(array(
                    'onlineGiftts' => $privateState->onlineGiftts,
                    'onlineGiftIDs' => $privateState->onlineGiftIDs,
                    "reward" => $giftData->rewardstr,
                    'gold' => $user->base()->gold,
                    'cash' => $user->base()->cash,
                    'tili' => $user->base()->tili,
                    'store' => $user->store(),
                    'hero' => $user->heros()
        ));                                                                     # 设置返回值
    }

    /**
     * 清理/重置 在线礼包时间戳
     */
    static private function ClearOnlineGiftTs() {
        ctx()->privateState->onlineGiftts = 0;
        ctx()->privateState->onlineGiftIDs = array();
        ctx()->privateState->onlineTs = 0;
    }

// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="    兑换码     ">

    /**
     * [6512]凭兑换码领取礼包
     */
    static function drawActivePackageByCode() {
        $user = new Data_UserGame(ctx());
        $privateState = new Info_PrivateState($user->privateState);             # 快速访问
        list($activeId, $codestring) = req()->paras;                            # 取参数 活动id, 兑换码

        $codePlatStr = "";
        $packageID = 0;
        if (self::PublicTokenCodeCheck($codestring)) {
            $packageInfo = GameConfig::token_PublicGift_getItem($codestring);
            my_Assert($packageInfo->expirets >= now() && $packageInfo->startTs <= now(),
                    ErrCode::active_activecode_outtime);
            my_Assert(!in_array($codestring, ctx()->privateState->usedTokens), ErrCode::active_hasgetted); # 已经领取过该礼包了
            $packageID = $codestring;
            $err = StoreProc::AddMultiItemInStore($packageInfo->reward);            # 发放礼包
            my_Assert(ErrCode::ok == $err, $err);
        } else {
            $active = GameConfig::activity_getItem($activeId);                      # 活动数据
            my_Assert(null != $active, ErrCode::active_const_no_err);
            my_Assert($active->startts <= now() && $active->endts >= now(), ErrCode::active_time); # 校验开放时间
            my_Assert(preg_match("/^[a-kmnp-z2-9]{10}$/", $codestring), ErrCode::active_activecode_format); # 基础格式校验(10个特定字符)
            $activeCode = CipheredBase32::Decode($codestring);                      # 解码
            $codePlatStr = GameConstants::GetPlatStringByActivteCode($activeCode);  # platstr
            my_Assert(GameConstants::AllPlatStr == $codePlatStr #                   # 忽略全平台礼包
                    || req()->getPlatStr() == $codePlatStr, #                       # 平台字符串必须相符
                    ErrCode::active_activecode_plat); #                             # 平台错误

            my_Assert(is_int($activeCode->number) #                                 # 编号为int值
                    && $activeCode->number >= 1 && $activeCode->number <= 50000, #  # 检查 兑换码的编号范围0~50000
                    ErrCode::active_activecode_format);

            $packageID = $activeCode->package;                                      # 礼包id
            $packageInfo = GameConfig::tokenGift_getItem($packageID);               # 礼包常量数据
            my_Assert(null != $packageInfo, ErrCode::err_const_no);                 # 防御
            my_Assert($packageInfo->expirets >= now() && $packageInfo->startTs <= now(),
                    ErrCode::active_activecode_outtime);                            # 激活码已经失效,或者礼包尚未开启
            my_Assert(!in_array($packageID, $privateState->usedTokens), ErrCode::active_hasgetted); # 已经领取过该礼包了
            my_Assert(!self::checkActiveCodeIsUsed($activeCode), ErrCode::active_activecode_used);  # 检查 该激活码是否别人已经使用过了
            $err = StoreProc::AddMultiItemInStore($packageInfo->reward);            # 发放礼包
            my_Assert(ErrCode::ok == $err, $err);                                   # 防御发放礼包过程出错
            //ctx()->privateState->usedTokens[] = $packageID;                         # 记录领取记录
            $ok = self::setActiveCodeUserRecord($activeCode, req()->uid);           # 插入数据库
            my_Assert($ok, ErrCode::err_db);                                        # 数据库操作失败- 重试
        }
        ctx()->privateState->usedTokens[] = $packageID;

        UserProc::updateUserInfo();                                             # 回存玩家数据
        $user = new Data_UserGame(ctx());                                       # 重新取一下玩家数据.
        $ret = array(#                                                          # 返回值
            "plat" => $codePlatStr,
            "packageId" => $packageID,
            "reward" => $packageInfo->reward,
            'gold' => $user->base()->gold,
            'cash' => $user->base()->cash,
            'tili' => $user->base()->tili,
            'store' => $user->store,
            'hero' => $user->heros
        );
        return Resp::ok($ret);                                                  # 返回成功信息
    }

    public static function PublicTokenCodeCheck($codestring) {
        $dic = GameConfig::token_PublicGift();
        if (StlUtil::dictHasProperty($dic, $codestring)) {
            return true;
        }
        return false;
    }

    public static function drawActivePackageByPublicCode($codestring) {

    }

    /**
     * 检查兑换码是否已经使用过了
     * @param ActiveCode $activeCode
     * @return boolean true : 已经用过了, false : 激活码尚未使用过.
     */
    static function checkActiveCodeIsUsed($activeCode) {
        $sql = sprintf("`plat`='%d' and `package`='%d' and `number`='%d'", #       # where 子句
                $activeCode->plat, $activeCode->package, $activeCode->number);
        $rows = daoInst()
                ->select()
                ->from(self::tab_toke_gift)                                     # 表名
                ->where($sql)
                ->count();
        return $rows > 0;
    }

    /**
     * 将兑换码添加到使用记录中
     * @param ActiveCode $actvieCode
     * @param string $uid
     * @return boolean true: 操作成功, false: 操作失败
     */
    static function setActiveCodeUserRecord($actvieCode, $uid) {
        $actvieCode->uid = $uid;                                                # 添加uid
        $ret = daoInst()
                ->insert(self::tab_toke_gift)                                   # 表名
                ->data($actvieCode)
                ->exec();
        return $ret > 0;
    }

// </editor-fold>

    /**
     * [6503] 查询当前分区开放时间戳
     */
    private static function GetZonePublicTS() {
        $zoneInfo = GameConfig::zonelist_getItem(req()->zoneid);
        return Resp::ok($zoneInfo->publicTs);
    }

// <editor-fold defaultstate="collapsed" desc="  体力  ">

    /**
     * [6508] 刷新玩家体力
     */
    public static function RecoveryTili() {
        $useTili = req()->paras[0];
        ActiveProc::ChangeTili($useTili);

        UserProc::updateUserInfo();
        $result = array(
            'time' => ctx()->privateState->TiliTime,
            'tili' => ctx()->baseInfo->tili
        );
        $resp = Resp::ok($result);
        return $resp;
    }

    /**
     * 6520 每日购买体力 6次
     */
    public static function BuyTili() {
        my_Assert(ctx()->privateState->buyTiliNum < glc()->active_BuyTili_DailyNum, ErrCode::active_BuyTiliNumLimit);
        $num = ctx()->privateState->buyTiliNum;
        $list = explode('/', glc()->active_BuyTili_Cost);
        $cost = $list[$num];
        my_Assert(ctx()->base(true)->cash >= $cost, ErrCode::notenough_cash_msg);

        ctx()->base(true)->Consume_Cash($cost);
        ctx()->privateState->buyTiliNum += 1;

        $recoveryNum = glc()->active_BuyTili_RecoveryNum;
        self::ChangeTili($recoveryNum);

        UserProc::updateUserInfo();
        $result = array(
            'time' => ctx()->privateState->TiliTime,
            'tili' => ctx()->baseInfo->tili,
            'cash' => ctx()->baseInfo->cash,
            'buyTiliNum' => ctx()->privateState->buyTiliNum,
        );
        $resp = Resp::ok($result);
        return $resp;
    }

    /**
     * 6521 刷新当前体力
     * @return type
     */
    public static function GetCurTili() {
        self::ChangeTili(0);

        UserProc::updateUserInfo();
        $result = array(
            'time' => ctx()->privateState->TiliTime,
            'tili' => ctx()->baseInfo->tili,
        );
        $resp = Resp::ok($result);
        return $resp;
    }

    /**
     * 清理每天的赠送体力领取记录
     * 每日重置购买体力次数
     */
    private static function ClearDailyTiliGift() {
        ctx()->privateState->dailyDrawedTiliGift = ArrayInit();
        ctx()->privateState->buyTiliNum = 0;
        ctx()->privateState->tiliRecord = 0;
    }

    /**
     * 修改玩家体力
     * @param int $useTili $useTili>0代表增加体力,   $useTili<0代表消耗体力
     */
    public static function ChangeTili($useTili) {
        $user = ctx();
        $moreTili = 0;                                                          # 超上限的体力值
        $tsNow = time();                                                        # 当前时间戳
// 如果没有tilitime这个值,说明是以前老用户新登录的,为了纠错在判断里面补值.(正常用户不会进入判断内部)
        if (!CommUtil::isPropertyExists($user->privateState, "TiliTime")) {
            $user->privateState->TiliTime = $tsNow - glc()->TiliMaxVal * glc()->active_Tili_RecoverTS;
        }
        if ($user->baseInfo->tili >= glc()->TiliMaxVal) {                       # 如果该账户体力值本身是大于上限的,获取一下超出的体力值
            $moreTili = $user->baseInfo->tili - glc()->TiliMaxVal;              # 用moreTili保存一下额外的体力值
            $user->privateState->TiliTime = $tsNow;                             # 重置下体力time
        }
        $useTime = $tsNow - $user->privateState->TiliTime;                      # 距离上次修改体力值的时间
        $recoverSpan = glc()->active_Tili_RecoverTS;                            # 恢复一点体力所需时间(一般8分钟)
        if ($useTime > $recoverSpan) {                                          # 该账户超过了单位体力时间,需要重新计算体力值
            if ($moreTili <= 0) {
                $user->baseInfo->tili += (int) ( (int) ($useTime / $recoverSpan));
                if ($user->baseInfo->tili > glc()->TiliMaxVal) {                # 检查体力值上限
                    $user->baseInfo->tili = glc()->TiliMaxVal;
                } // 这代码真烂,以后用的时候再修复吧... -gwang 20200110154858
            }
            $user->privateState->TiliTime = $tsNow;
        }
        if ($useTili < 0) {                                                     # 如果是消耗体力
            my_Assert(abs($useTili) <= $user->baseInfo->tili, ErrCode::notenough_tili);   # 体力不足
            $user->baseInfo->tili += $useTili;                                            # 扣除体力

            SystemProc::CostTiliRecord(req()->zoneid, ctx()->baseInfo->name, $useTili);
        } else if ($useTili > 0) {                                              # 如果是购买增加体力
            $user->baseInfo->tili += $useTili;
        }
        NormalEventProc::OnTiliChange($user->baseInfo->tili);
        return ErrCode::ok;
    }

// </editor-fold>
//
//
// <editor-fold defaultstate="collapsed" desc="    7日签到   ">

    /**
     *  重置7日签到相关计数器
     */
    static function DailyResetDay7Task() {
        ctx()->gates->Times = 0;
        $typeID = 6;                                                            #  7日活动
        $ac = GameConfig::activity_getItem($typeID);
        my_Assert(null != $ac, ErrCode::err_const_no);
        $startDay = totalDays($ac->startts);
        $newLoginDays = array_filter(ctx()->privateState->LoginDays, #          # 剔除不符合时间的登录记录
                function ($tsday)use ($startDay) {
                    return $startDay <= $tsday;
                }
        );
        ctx()->privateState->LoginDays = $newLoginDays;                         #
        if (count(ctx()->privateState->LoginDays) < 7) {
            ctx()->privateState->LoginDays[] = totalDays();
        }
    }

    /**
     * [6502] 领取七日签到奖励
     */
    static function Day7_DrawReward() {
        // 设计7日数据结构
        list($day) = req()->paras;                                              # 参数: 领取第x天的奖励
        $user = ctx();
        $private = new Info_PrivateState($user->privateState);                  # 私有数据
        my_Assert(count($private->LoginDays) >= $day, ErrCode::active_day7_totaldays);
        my_Assert(!in_array($day, $private->day7_drawed), ErrCode::active_hasgetted);
        $day_rwd = GameConfig::activity_day7_getItem($day);                     # 查询奖励数据
        my_Assert(null != $day_rwd, ErrCode::err_const_no);                     # 防御找不到配置
        StoreProc::AddMultiItemInStore($day_rwd->reward);                       # 发放奖励
        $private->day7_drawed[] = $day;                                         # 添加领取记录
        $user->privateState = $private;                                         # 更新数据
        UserProc::updateUserInfo();                                             # 回存
        return Resp::ok(array(
                    'gold' => $user->baseInfo->gold,
                    'cash' => $user->baseInfo->cash,
                    'tili' => $user->baseInfo->tili,
                    'store' => $user->store,
                    'hero' => $user->heros
        ));                                                                     # 返回值
    }

// </editor-fold>
//
// <editor-fold defaultstate="collapsed" desc="    等级礼包    ">

    /**
     * 6501 活动 - 等级礼包: 领取奖励
     */
    private static function GetLevelGift() {
        list($giftId) = req()->paras;                                           # 提取参数: 礼包id
        $mo = GameConfig::activity_levelgift_getItem($giftId);
        my_Assert(null != $mo, ErrCode::active_const_no_err);                   # 配置数据

        my_Assert($mo->level <= ctx()->base()->level, ErrCode::user_levelnotenough_msg); # 校验玩家等级

        my_Assert(!in_array($giftId, ctx()->privateData()->gettedLevelGiftIds), ErrCode::active_hasgetted); # 尚未领取

        StoreProc::AddMultiItemInStore($mo->rewardstr, 6);                      # 发放道具
        ctx()->privateData(true)->gettedLevelGiftIds[] = $giftId;               # 添加领取记录
        UserProc::updateUserInfo();                                             # 回存数据

        return Resp::ok(array('gold' => ctx()->base()->gold,
                    'cash' => ctx()->base()->cash));
    }

// </editor-fold>
}
