<?php

namespace Cas\Module;

use KIF\Core\Request;
use KIF\Page\Page;
use KIF\Verify;
use Cas\Dao\LotteryEvents;
use KIF\Core\Config;
use KIF\Image;
use Cas\Dao\LotteryPrize;
use KIF\Cache\Memcached;
use KIF\Dao\SqlHelper;
use Cas\Dao\LotteryPrizeVirtualData;
use Cas\Dao\LotteryData;
use Cas\Module\LotteryLog;
use Cas\Dao\LotteryEventsLog as DLog;
/**
 *
 *
 * 抽奖 模型
 *
 * @author lihuanchun
 */
class LotteryDraw  {
	
	private $objMemcached;
	
	private $objRank;
	
	private $uid;
	
	private $eventsId;
	
	private $objDLotteryEvents;
	
	private $objMlottery;
	
	private $objDLotteryPrizeVirtualData;
	
	private $objMLotteryEventsLimitations;
	
	private $objDLotteryData;
	
	private $objMLotteryLog;
	
	private $version;
	
	private $thisTime;
	
	public function __construct($uid=null , $eventsId=null ) {
		$this->objMemcached = new Memcached();
		$this->objRank = new Rank();
		$this->uid = $uid;
		$this->eventsId = $eventsId;
		$this->objDLotteryEvents = new LotteryEvents();
		$this->objDLotteryPrize = new LotteryPrize();
		$this->objDLotteryPrizeVirtualData = new LotteryPrizeVirtualData();
		$this->objDLotteryData = new LotteryData();
		$this->objMlottery = new Lottery();
		$this->objMLotteryEventsLimitations = new LotteryEventsLimitations();
		$this->objMLotteryLog = new LotteryLog($uid,$eventsId);
		$this->version = '0.1';
		$this->thisTime = time();
	}
	
	
	public function verifyPrize(){
		
		$eventsAndPrize =  $this->objMlottery->getOneLotteryEventsAndPrize($this->eventsId);
		# 活动是否开始
		if($this->thisTime < $eventsAndPrize['events']['begin_time'] || $this->thisTime > $eventsAndPrize['events']['end_time']){
			return false;
		}
		# 活动限制
		if(!$this->objMLotteryEventsLimitations->ckEventRestrictions($this->uid,Request::ip(), $this->eventsId)){
			return false;
		}
		
		
		# 排列顺序
		$newPrize = array();
		foreach($eventsAndPrize['prize'] as $prize){
			$prize_id = $prize['id'];
			$begin_hour = $prize['begin_hour'];
			$end_hour = $prize['end_hour'];
			$this_hour = date("H",$this->thisTime);
		
			# 获奖是否在此抽奖时间段
			if(!($this_hour >=$begin_hour && $this_hour<$end_hour)){
				continue;
			}
			
			# 验证当前奖项是否显示
			if($prize['display']==LotteryPrize::PRIZE_DISPLAY_HIDE){
				continue;
			}
			# 验证当前将奖项 库存数量
			if($prize['prize_num']-$prize['prize_winning_num'] <= 0){
				continue;
			}
			# 验证是否在 黑 & 白  名单中
			if($this->ckBlackAndWhiteList($prize_id) == false){
				continue;
			}
			# 获取下一次的中奖时间 【开始抽奖逻辑】
			$nextWinTime = $this->getNextWinTime($prize_id);
			$newPrize[$nextWinTime] = $prize_id;
		}
		
		# 中奖顺序
		ksort($newPrize,SORT_NUMERIC);
		foreach($newPrize as $key => $this_prize_id){
			$newPrize[$key] = $eventsAndPrize['prize'][$this_prize_id];
		}
		
		foreach($newPrize as $prize){
			$prize_id = $prize['id'];
			$begin_hour = $prize['begin_hour'];
			$end_hour = $prize['end_hour'];
			$this_hour = date("H",$this->thisTime);
			
			
			# 获奖是否在此抽奖时间段
			if(!($this_hour >=$begin_hour && $this_hour<$end_hour)){
				continue;
			}
			# 验证当前奖项是否显示
			if($prize['display']==LotteryPrize::PRIZE_DISPLAY_HIDE){
				continue;
			}
			# 验证当前将奖项 库存数量
			if($prize['prize_num']-$prize['prize_winning_num'] <= 0){
				continue;
			}
			# 验证是否在 黑 & 白  名单中
			if($this->ckBlackAndWhiteList($prize_id) == false){
				continue;
			}
			# 获取下一次的中奖时间 【开始抽奖逻辑】
			$nextWinTime = $this->getNextWinTime($prize_id);
			if (!$this->lock($prize_id)) return false;
			if (!$nextWinTime) {
				$isWin = false;
				$this->setNextWinTime($prize_id);
			} elseif ($nextWinTime <= $this->thisTime) {
				$isWin = true;
				# 发奖
				$lotteryDataId = $this->awards($prize_id,$nextWinTime);
				$this->setNextWinTime($prize_id);
				$this->unlock($prize_id);
				return $lotteryDataId;
				break;
			} 
			
			
			# 检查是否百分之百中奖用户名单中
			if($this->ckHundredPercentList($prize_id)){
				$isWin = true;
				# 发奖
				$lotteryDataId = $this->awards($prize_id,$this->thisTime);
				$this->setNextWinTime($prize_id);
				$this->unlock($prize_id);
				return $lotteryDataId;
				break;
			}
			$this->unlock($prize_id);
			continue;
		}
		return false;
	}
	
	
	/**
	 * 清除下次中奖时间 并且动态计算下次中奖时间
	 */
	public function clear_draw_next_time($prize_id) {
		$memkey = $this->getCacheKeyOfTimeBucketWinTimes($prize_id);
		$this->objMemcached->delete($memkey);
		$memkey = $this->getCacheKeyOfNextWinTime($prize_id);
		$this->objMemcached->delete($memkey);
		$this->setNextWinTime($prize_id);
	}
	
	
	/**
	 * 检查是否是百分百中奖名单中的用户
	 */
	public function ckHundredPercentList($prize_id){
		// 查看百分百中奖名单中的用户
		$hundred_percent_list = $this->objMemcached -> get('lottery_prize_'.$prize_id.'_hundred_percent_list');
			
		if(!empty($hundred_percent_list)){
				
			if(isset($hundred_percent_list[$this->uid])){
				return true;
			}
				
		}
		return false;
	}
	
	
	/**
	 * 检查白名单 & 黑名单
	 */
	public function ckBlackAndWhiteList($prize_id){
		// 查看黑名单
		$black_list = $this->objMemcached -> get('lottery_prize_'.$prize_id.'_black_list');
			
		if(!empty($black_list)){
			if(isset($black_list[$this->uid])){
				return false;
			}
		}
		// 查看白名单
		$white_list = $this->objMemcached -> get('lottery_prize_'.$prize_id.'_white_list');
		if(!empty($white_list)){
			if(!isset($white_list[$this->uid])){
				return false;
			}
		}
		return true;
	}

	
	/**
	 * 发奖逻辑
	 */
	public function awards($prize_id,$winTime){
		$eventsAndPrize =  $this->objMlottery->getOneLotteryEventsAndPrize($this->eventsId);
		$info = array(
				'events_id' => $this->eventsId,
				'prize_id' => $prize_id,
				'uid' => $this->uid,
				'winners_time' => $winTime,
				'winning_time' => $this->thisTime,
				'run_time_data' => $eventsAndPrize,
		);
		$prize = $eventsAndPrize['prize'][$prize_id];
		if($prize['type'] == LotteryPrize::TYPE_ENTITY){
			$virtual_condition = "prize_id = {$prize_id} AND lottery_data_id = 0 " ;
			$LotteryPrizeVirtualDataID = $this->objDLotteryPrizeVirtualData->findIdsBy ( $virtual_condition, '0,1' ,'id desc');
			$LotteryPrizeVirtualDataID = array_pop($LotteryPrizeVirtualDataID);
			$prizeVirtualData = $this->objDLotteryPrizeVirtualData->get($LotteryPrizeVirtualDataID);
			$info['virtual_data'] = $prizeVirtualData['data'];
			$info['create_time'] = $this->thisTime;
		}
		$lotteryDataId = $this->objDLotteryData -> add($info);
		# 判断是否是 虚拟类
		if($prize['type'] == LotteryPrize::TYPE_ENTITY){
			$virtualInfo = array(
					'uid' => $this->uid,
					'lottery_data_id' => $lotteryDataId,
					'events_id' => $this->eventsId,
			);
			$this->objDLotteryPrizeVirtualData->modify($virtualInfo,array('id' => $LotteryPrizeVirtualDataID));
		}
		$this->objDLotteryPrize -> upPrizeWinningNum($prize_id, 1);
		
		# 用户记录
		$this->objMLotteryEventsLimitations->setUserWinningNum($this->uid, $this->eventsId);
		
		
		# 记录一条获奖日志
		$other = $info;
		$this->objMLotteryLog ->addLog(DLog::LOG_TYPE_RECEIVE, $other);
		
		
		return $lotteryDataId;
	}
	
	
	/**
	 * 开启抽奖锁
	 * @return boolean | null
	 */
	public function lock($prize_id) {
		return $this->objMemcached->add($this->getCacheKeyOfLock($prize_id), true, 10);
	}
	
	/**
	 * 关闭抽奖锁
	 * @return boolean | null
	 */
	public function unlock($prize_id) {
		return $this->objMemcached->delete($this->getCacheKeyOfLock($prize_id));
	}
	
	/**
	 * 获取抽奖锁 cache key
	 * @return string
	 */
	public function getCacheKeyOfLock($prize_id) {
		return "lottery_draw_lock_{$prize_id}";
	}
	
	/**
	 * 设置当天下次中奖时间
	 * @return boolean | null
	 */
	public function setNextWinTime($prize_id) {
		$hasWinTotal = $this->objDLotteryData->getTodayHasWinTotal($prize_id);
		$timeBucketWinTimes = $this->getTimeBucketWinTimes($prize_id);
		$next_win_time = $this->objRank->winnerCal($timeBucketWinTimes, $hasWinTotal);
		return $this->objMemcached->set($this->getCacheKeyOfNextWinTime($prize_id), $next_win_time, 60*60*24);
	}
	
	/**
	 * 获取当天每个时间断中奖次数
	 * @return array
	 */
	public function getTimeBucketWinTimes($prize_id) {
		$memkey = $this->getCacheKeyOfTimeBucketWinTimes($prize_id);
		$timeBucketWinTimes = $this->objMemcached->get($memkey);
		if (!$timeBucketWinTimes) {
			$replyInfo =  $this->objDLotteryPrize->get ( $prize_id ); // 获取当前奖项详情
			$eventsData = $this->objDLotteryEvents->get($this->eventsId);
			$gift_amount = $replyInfo['prize_num'];
			
			if ($gift_amount <= 0) {
				return false;
			}
			$start_time = $eventsData['start_time'];
			$end_time = $eventsData['end_time'];
			$today_time = mktime(0,0,0);
			$overTotal = ceil(($end_time - $today_time) / (60*60*24));//剩余天数
			$hasWinTimes = $replyInfo['prize_winning_num'];
			$todayHasWinTimes =  $this->objDLotteryData->getTodayHasWinTotal($prize_id);
			$needWinTimes = ceil(($gift_amount - $hasWinTimes) / $overTotal) - $todayHasWinTimes;
			$timeBucketWinTimes = $this->objRank->getTimeValue($needWinTimes, date('G'), $replyInfo['end_hour']-1);
			$this->objMemcached->set($memkey, $timeBucketWinTimes, 60 * 60 * 24);
		}
		return $timeBucketWinTimes;
	}
	
	/**
	 * 获取当天中奖数
	 */
	public function getCacheKeyOfTimeBucketWinTimes($prize_id){
		return date('Y_m_d',$this->thisTime).'_'.$prize_id.'_winning_num';
	}
	
	/**
	 * 获取下次中奖时间
	 * @return string
	 */
	public function getNextWinTime($prize_id) {
		$next_win_time = $this->objMemcached->get($this->getCacheKeyOfNextWinTime($prize_id));
		return $next_win_time;
	}
	
	
	/**
	 * cache中下次中奖时间的key
	 */
	public function getCacheKeyOfNextWinTime($prize_id){
		return date('Y_m_d',$this->thisTime).'_'.$prize_id.'_next_time';
	}
	
	
}