<?php
!defined('P_W') && exit('Forbidden');

/**
 * 評價服務
 *
 * @package Rate
 */
class PW_Rate {
	var $_cache = TRUE; //是否開啟文件緩存

	/**
	 * 獲取一條評價選項(配置)記錄
	 *
	 */
	function getRateConfig($typeId, $id) {
		$id = intval($id);
		if ($id < 1) {
			return null;
		}
		$rateConfigDb = $this->_getRateConfigDB();
		return ($this->_cache) ? $this->_get_RateConfigCache($typeId, $id) : $rateConfigDb->get($id);
	}
	/**
	 * 增加一條評價選項(配置)記錄
	 *
	 */
	function addRateConfig($fieldData) {
		$fieldData = $this->_checkRateConfig($fieldData);
		if ($fieldData === FALSE) {
			return null;
		}
		$rateConfigDB = $this->_getRateConfigDB();
		$result = $rateConfigDB->add($fieldData);
		if ($this->_cache && $result) {
			$this->_set_RateConfigCache();
		}
		return $result;
	}
	function _checkRateConfig($fieldData) {
		$fieldData['title'] = trim($fieldData['title']);
		$fieldData['icon'] = trim($fieldData['icon']);
		$fieldData['isopen'] = intval($fieldData['isopen']); //是否開啟
		$fieldData['typeid'] = intval($fieldData['typeid']); //類型
		if ($fieldData['title'] == "" || $fieldData['icon'] == "" || !in_array($fieldData['typeid'], $this->_getRateType()) || !in_array($fieldData['isopen'], array(
			0,
			1
		))) {
			return FALSE;
		}
		$fieldData['creditset'] = intval($fieldData['creditset']); //這邊的約束
		$fieldData['voternum'] = intval($fieldData['voternum']); //評價者積分
		$fieldData['authornum'] = intval($fieldData['authornum']); //作者積分
		if ($fieldData['voternum'] > 10 || $fieldData['voternum'] < - 10 || $fieldData['authornum'] > 10 || $fieldData['authornum'] < - 10) {
			return FALSE;
		}
		$fieldData['creator'] = trim($fieldData['creator']);
		$fieldData['updater'] = trim($fieldData['updater']);
		$rateConfigDB = $this->_getRateConfigDB();
		if (!$this->_isAllowFields($fieldData, $rateConfigDB->getStruct())) {
			return FALSE;
		}
		$fieldData['created_at'] = $fieldData['update_at'] = time();
		return $fieldData;
	}
	function _isAllowFields($sourceFields, $allowFields) {
		foreach($sourceFields as $key => $value) {
			if (!in_array($key, $allowFields)) {
				return FALSE;
			}
		}
		return TRUE;
	}
	/**
	 * 更新一條評價選項(配置)記錄
	 *
	 */
	function updateRateConfig($fieldData, $id) {
		$id = intval($id);
		$rateConfigDB = $this->_getRateConfigDB();
		if ($id < 1 || !$this->_isAllowFields($fieldData, $rateConfigDB->getStruct())) {
			return null;
		}
		$result = $rateConfigDB->update($fieldData, $id);
		if ($this->_cache && $result) {
			$this->_set_RateConfigCache();
		}
		return $result;
	}
	/**
	 * 刪除一條評價選項(配置)記錄
	 *
	 */
	function deleteRateConfig($id) {
		$id = intval($id);
		if ($id < 1) {
			return null;
		}
		$rateConfigDB = $this->_getRateConfigDB();
		$result = $rateConfigDB->delete($id);
		if ($this->_cache && $result) {
			$this->_set_RateConfigCache();
		}
		return $result;
	}
	/**
	 * 跟據類型獲取評價(配置)選項記錄
	 *
	 */
	function getsRateConfigByTypeId($typeId) {
		$typeId = intval($typeId);
		if ($typeId < 1) {
			return null;
		}
		$rateConfigDB = $this->_getRateConfigDB();
		//@todo 是否開啟文件緩存
		if (!$this->_cache || !$rateConfigs = $this->_get_RateConfigCache($typeId)) {
			$rateConfigs = $rateConfigDB->getsByTypeId($typeId);
		}
		if (!$rateConfigs) {
			return null;
		}
		$tmp = array();
		foreach($rateConfigs as $config) {
			$config['tips'] = $this->_buildTips($config);
			$tmp[] = $config;
		}
		return $tmp;
	}
	function _buildTips($config) {
		$creditNames = $this->getCreditDefaultMap();
		$creditName = $creditNames[$config['creditset']];
		$tips = array();
		$tips[] = "評價者" . $creditName . $this->_setPrefix($config['voternum']);
		$tips[] = "作者" . $creditName . $this->_setPrefix($config['authornum']);
		return implode("，", $tips);
	}
	function _setPrefix($value) {
		return ($value > 0) ? "+" . $value : $value;
	}
	/**
	 * 增加一條評價記錄
	 * 先加點再存log
	 *
	 */
	function addRate($userId, $objectId, $optionId, $typeId, $ip, $anonymity = FALSE) {
		//記錄是否已經存在 沒有則新增，否則更新
		//先檢查用戶是否評價
		//@todo 檢查對象的有效性 並獲取對象作者的ID
		global $credit;
		if (!$authorId = $this->_checkObjectByTypeId($typeId, $objectId)) {
			return null;
		}
		//再檢查評價結果記錄是否存在
		if (!$this->getRateResultByOptionId($optionId, $objectId)) {
			$fieldData = array(
				'objectid' => $objectId,
				'optionid' => $optionId,
				'typeid' => $typeId,
				'num' => 1
			);
			$this->addRateResult($fieldData);
		} else {
			$this->updateRateResultByOptionId($optionId, $objectId);
		}
		$fieldData = array(
			'objectid' => $objectId,
			'optionid' => $optionId,
			'typeid' => $typeId,
			'uid' => $userId,
			'created_at' => time(),
			'ip' => $ip
		);
		$fieldData = $this->_checkRate($fieldData, $anonymity);
		if ($fieldData === FALSE) {
			return null;
		}
		$rateDB = $this->_getRateDB();
		$rateDB->add($fieldData);
		// TODO 增加對應的金幣或積分等
		//獲取配置信息 是否讀取緩存／或數據庫
		if (!$this->_cache || !$config = $this->_get_RateConfigCache($typeId, $optionId)) {
			$config = $this->getRateConfig($typeId, $optionId);
		}
		require_once S::escapePath(R_P . "require/credit.php");
		if ($config['creditset'] < 0) {
			$creditMap = array_flip($this->_getCreditMap());
			$cType = $creditMap[$config['creditset']];
		} else {
			$cType = $config['creditset'];
		}
		(!$anonymity) && $credit->set($userId, $cType, $config['voternum']);
		$credit->set($authorId, $cType, $config['authornum']);
		//熱榜關聯@todo
		$this->_addRateForHot($objectId, $typeId, $optionId);
		return $this->_buildTips($config);
	}
	/*******************************評價功能熱榜*start*****************************************/
	/**
	 * 獲取某類型下評價選項列表，如果指定選項ID則直接獲取選項的action
	 * 返回帖子實例︰array("rateThread_1" => "最感動","rateThread_2" => "最高興")
	 * 返回日志實例︰array("rateDiary_10" => "最感動","rateDiary_12" => "最高興")
	 * 返回照片實例︰array("ratePicture_20" => "最感動","ratePicture_21" => "最高興")
	 * 其中KEY(如︰rateThread_1)為熱榜app數據表中的action值
	 * 可直接組裝<select></select>
	 * @param int $typeId
	 * @param int $optionId
	 * @return array or string
	 */
	function _getRateTypesForHot($typeId, $optionId = FALSE) {
		$configs = $this->getsRateConfigByTypeId($typeId);
		$prefix = ($typeId == 1) ? "rateThread_" : (($typeId == 2) ? "rateDiary_" : "ratePicture_");
		$newConfigs = $actions = array();
		foreach($configs as $config) {
			$ratePrefix = $prefix . $config['id'];
			$actions[$config['id']] = $ratePrefix;
			$newConfigs[$ratePrefix] = $config['title'];
		}
		return ($optionId) ? $actions[$optionId] : $newConfigs;
	}
	function _addRateForHot($objectId, $typeId, $optionId) {
		$action = $this->_getRateTypesForHot($typeId, $optionId);
		require_once (R_P . 'require/functions.php');
		updateDatanalyse($objectId, $action, 1);
	}
	// 帖子
	function getRateThreadHotTypes() {
		return $this->_getRateTypesForHot(1);
	}
	// 日志
	function getRateDiaryHotTypes() {
		return $this->_getRateTypesForHot(2);
	}
	// 照片
	function getRatePictureHotTypes() {
		return $this->_getRateTypesForHot(3);
	}
	/*******************************評價功能熱榜*end*****************************************/
	function _checkRate($fieldData, $anonymity) {
		$fieldData['objectid'] = intval($fieldData['objectid']);
		$fieldData['optionid'] = intval($fieldData['optionid']);
		$fieldData['typeid'] = intval($fieldData['typeid']);
		$fieldData['uid'] = intval($fieldData['uid']);
		if (!$anonymity && $fieldData['uid'] < 0) {
			return FALSE;
		}
		$rateDB = $this->_getRateDB();
		if ($fieldData['objectid'] < 0 || !in_array($fieldData['typeid'], $this->_getRateType()) || $fieldData['optionid'] < 0 || !$this->_isAllowFields($fieldData, $rateDB->getStruct())) {
			return FALSE;
		}
		$fieldData['created_at'] = time();
		return $fieldData;
	}
	/**
	 * 根椐用戶名獲取評價記錄
	 *
	 */
	function getsRateByUserId($userId, $objectId, $typeId) {
		$userId = intval($userId);
		$objectId = intval($objectId);
		$typeId = intval($typeId);
		if ($typeId < 1 || $userId < 1 || $objectId < 1) {
			return null;
		}
		$rateDB = $this->_getRateDB();
		return $rateDB->getsByUserId($userId, $objectId, $typeId);
	}
	/**
	 * 統計本周之最
	 *
	 */
	function getRateByWeek($typeId) {
		$typeId = intval($typeId);
		if ($typeId < 1) {
			return null;
		}
		$rateDB = $this->_getRateDB();
		$RateResult = $rateDB->getFromTmpTableByWeek($typeId);
		//$RateResult = $this->_getRateDB ()->getByWeek ( $typeId );
		if (!$RateResult) {
			return null;
		}
		$tmp = array();
		foreach($RateResult as $result) {
			//根椐對象ID獲取對象標題和作者
			$result['objectInfo'] = $this->_getObjectByTypeId($typeId, $result['objectid']);
			$tmp[$result['optionid']] = array_merge($result['objectInfo'], $result);
		}
		return $tmp;
	}
	/*************************數據處理區域 start********************************/
	function _getObjectByTypeId($typeId, $objectId) {
		switch ($typeId) {
			case 1:
				return $this->_getThreadById($objectId);
				break;

			case 2:
				return $this->_getDiaryByById($objectId);
				break;

			case 3:
				return $this->_getPhotoById($objectId);
				break;

			default:
				return array();
		}
		return array();
	}
	function _getThreadById($tid) {
		$rateDB = $this->_getRateDB();
		$thread = $rateDB->_db->get_one("SELECT * FROM pw_threads WHERE tid={$tid}");
		if (!$thread) {
			return array();
		}
		$result = array();
		$result['title'] = $thread['subject'];
		$result['href'] = "/read.php?tid=" . $tid;
		$result['author'] = $thread['author'];
		$result['authorUrl'] = "/".USER_URL. $thread['authorid']; //authorid
		return $result;
	}
	function _getDiaryByById($did) {
		$rateDB = $this->_getRateDB();
		$diary = $rateDB->_db->get_one("SELECT * FROM pw_diary WHERE did={$did}");
		if (!$diary) {
			return array();
		}
		$result = array();
		$result['title'] = $diary['subject'];
		$result['href'] = "/apps.php?q=diary&u=" . $diary['uid'] . "&did=" . $did;
		$result['author'] = $diary['username'];
		$result['authorUrl'] = "/".USER_URL. $diary['uid']; //1
		return $result;
	}
	function _getPhotoById($pid) {
		$rateDB = $this->_getRateDB();
		$photo = $rateDB->_db->get_one("SELECT * FROM pw_cnphoto WHERE pid={$pid}");
		if (!$photo) {
			return array();
		}
		$album = $rateDB->_db->get_one("SELECT * FROM pw_cnalbum WHERE aid=" . $photo['aid']);
		$result = array();
		$result['title'] = (isset($photo['pintro']) && trim($photo['pintro']) != "") ? $photo['pintro'] : '暫無描述';
		//$result ['href'] = "/apps.php?q=photos&a=view&pid=" . $pid;
		$result['href'] = "/apps.php?q=photos&space=1&u=" . $album['ownerid'] . "&a=view&pid=" . $pid;
		$result['author'] = $photo['uploader'];
		$result['authorUrl'] = "/".USER_URL. $album['ownerid'];
		return $result;
	}
	function _checkObjectByTypeId($typeId, $objectId) {
		switch ($typeId) {
			case 1:
				return $this->_checkThreadById($objectId);
				break;

			case 2:
				return $this->_checkDiaryByById($objectId);
				break;

			case 3:
				return $this->_checkPhotoById($objectId);
				break;

			default:
				return FALSE;
		}
		return TRUE;
	}
	function _checkThreadById($tid) {
		$rateDB = $this->_getRateDB();
		$thread = $rateDB->_db->get_one("SELECT * FROM pw_threads WHERE tid={$tid}");
		if (!$thread || !isset($thread['authorid'])) {
			return FALSE;
		}
		return $thread['authorid'];
	}
	function _checkDiaryByById($did) {
		$rateDB = $this->_getRateDB();
		$diary = $rateDB->_db->get_one("SELECT * FROM pw_diary WHERE did={$did}");
		if (!$diary || !isset($diary['uid'])) {
			return FALSE;
		}
		return $diary['uid'];
	}
	function _checkPhotoById($pid) {
		$rateDB = $this->_getRateDB();
		$photo = $rateDB->_db->get_one("SELECT * FROM pw_cnphoto WHERE pid={$pid}");
		if (!$photo) {
			return FALSE;
		}
		$album = $rateDB->_db->get_one("SELECT * FROM pw_cnalbum WHERE aid=" . $photo['aid']);
		if (!$album || !isset($album['ownerid'])) {
			return FALSE;
		}
		return $album['ownerid'];
	}
	function addConfigPower($powerData, $groupData) {
		setConfig('db_ratepower', serialize($powerData));
		setConfig('db_rategroup', serialize($groupData));
		updatecache_c();
	}
	function getUserGroupLevel() {
		$rateDB = $this->_getRateDB();
		$query = $rateDB->_db->query("SELECT gid,gptype,grouptitle,groupimg,grouppost FROM pw_usergroups ORDER BY grouppost,gid");
		$userGroups = $rateDB->_getAllResultFromQuery($query);
		$tmp = array();
		foreach($userGroups as $group) {
			if ($group['gptype'] == 'default' && $group['gid'] != 2) {
				continue;
			}
			if ($group['gptype'] == 'system' && $group['gid'] == 3) {
				continue;
			}
			$group['defaultTimes'] = ($group['gptype'] == 'member' && $group['gid'] == 8) ? 5 : 20;
			$tmp[$group['gptype']][] = $group;
		}
		//排序
		$groups = array();
		$groups['member'] = $tmp['member'];
		$groups['system'] = $tmp['system'];
		$groups['special'] = $tmp['special'];
		$groups['default'] = $tmp['default'];
		return $groups;
	}
	function _getBaseDB() {
		require_once S::escapePath(dirname(__FILE__) . "/base/basedb.php");
		return new BaseDB();
	}
	/*************************數據處理區域 end********************************/
	/**
	 * 增加一條評價結果記錄
	 *
	 */
	function addRateResult($fieldData) {
		$fieldData = $this->_checkRateResult($fieldData);
		if ($fieldData === FALSE) {
			return null;
		}
		$rateResultDB = $this->_getRateResultDB();
		return $rateResultDB->add($fieldData);
	}
	function _checkRateResult($fieldData) {
		$fieldData['objectid'] = intval($fieldData['objectid']);
		$fieldData['optionid'] = intval($fieldData['optionid']);
		$fieldData['typeid'] = intval($fieldData['typeid']);
		if ($fieldData['objectid'] < 1 || $fieldData['optionid'] < 1 || !in_array($fieldData['typeid'], $this->_getRateType())) {
			return FALSE;
		}
		$fieldData['num'] = 1;
		return $fieldData;
	}
	function _getRateType() {
		return array(
			1,
			2,
			3
		);
	}
	/**
	 * 根椐對象ID和選項ID獲取評價記錄
	 *
	 */
	function getRateResultByOptionId($optionId, $objectId) {
		$objectId = intval($objectId);
		$optionId = intval($optionId);
		if ($optionId < 1 || $objectId < 1) {
			return null;
		}
		$rateResultDB = $this->_getRateResultDB();
		return $rateResultDB->getByOptionId($optionId, $objectId);
	}
	/**
	 * 根椐對象ID和選項ID更新評價記錄
	 *
	 */
	function updateRateResultByOptionId($optionId, $objectId) {
		$objectId = intval($objectId);
		$optionId = intval($optionId);
		if ($optionId < 1 || $objectId < 1) {
			return null;
		}
		$rateResultDB = $this->_getRateResultDB();
		return $rateResultDB->updateByOptionId($optionId, $objectId);
	}
	/**
	 * 根椐類型ID和選項ID獲取評價記錄
	 *
	 */
	function getRateResultByTypeId($typeId, $objectId) {
		$typeId = intval($typeId);
		$objectId = intval($objectId);
		if ($typeId < 1 || $objectId < 1) {
			return null;
		}
		$tmp = array();
		$total = 0; //評價人數
		$rateResultDB = $this->_getRateResultDB();
		$rateResults = $rateResultDB->getByTypeId($typeId, $objectId);
		if (!$rateResults) {
			return array(
				$tmp,
				$total
			);
		}
		foreach($rateResults as $result) {
			$total += $result['num'];
			$tmp[$result['optionid']] = $result;
		}
		return array(
			$tmp,
			$total
		);
	}
	/**
	 * 獲取積分設置對應表
	 * 主要是給每個積分選項設置一個唯一的key，用于數據存儲
	 * 系統默認的為負數，自定義的為其唯一的主鍵
	 * 同時提交某特定key的名稱
	 * @return unknown
	 */
	function getCreditDefaultMap($creditKey = null) {
		$map = $this->_getCreditMap();
		$creditNames = pwCreditNames();
		$tmp = array();
		foreach($creditNames as $key => $value) {
			if (in_array($key, array_keys($map))) {
				$tmp[$map[$key]] = $value;
				continue;
			}
			$tmp[$key] = $value;
		}
		return (array_key_exists($creditKey, $tmp)) ? $tmp[$creditKey] : $tmp;
	}
	function _getCreditMap() {
		return array(
			"money" => "-1",
			"rvrc" => "-2",
			"credit" => "-3",
			"currency" => "-4"
		);
	}
	/************************************文件緩存區域start***********************************************/
	function _set_RateConfigCache() {
		$rateConfigDB = $this->_getRateConfigDB();
		$configs = $rateConfigDB->gets();
		if (!$configs) {
			return null;
		}
		$tmp = array();
		foreach($configs as $config) {
			$tmp[$config['typeid']][] = $config;
		}
		//寫入緩存文件
		$result = serialize($tmp);
		pwCache::setData($this->_getReteConfigFilePath(), $result, false, 'w');
		return $result;
	}
	// 如果指定類型則返回對應的數據
	function _get_RateConfigCache($typeId = FALSE, $optionId = FALSE) {
		if (!file_exists($this->_getReteConfigFilePath()) || !$result = readover($this->_getReteConfigFilePath())) {
			$result = $this->_set_RateConfigCache();
		}
		$rateConfigs = unserialize($result);
		if (!$rateConfigs) {
			return FALSE;
		}
		//取特定某個分類型下特定的單個配置
		if ($optionId && $typeId && isset($rateConfigs[$typeId])) {
			foreach($rateConfigs[$typeId] as $config) {
				if ($config['id'] == $optionId) {
					return $config;
				}
			}
		}
		//只取某個類型的配置
		if (isset($rateConfigs[$typeId]) && in_array($typeId, $this->_getRateType())) {
			return $rateConfigs[$typeId];
		}
		return $rateConfigs;
	}
	function _getReteConfigFilePath() {
		return D_P . 'data/bbscache/rate_config.php';
	}
	/***********************************************************************************/
	function countByUserId($userId) {
		if (intval($userId) < 1) {
			return -1;
		}
		$rateDB = $this->_getRateDB();
		return $rateDB->countByUserId($userId);
	}
	function countByIp($ip) {
		if ($ip == "") {
			return -1;
		}
		$rateDB = $this->_getRateDB();
		return $rateDB->countByIp($ip);
	}
	function getsByIp($ip, $objectId, $typeId) {
		$rateDB = $this->_getRateDB();
		return $rateDB->getsByIp($ip, $objectId, $typeId);
	}
	/**********************************************************/
	function getWeekData($typeId, $hotSource = true) {
		if ($hotSource) {
			return $this->getWeekResultHtmlFromHot($typeId);
		}
		return $this->getRateByWeek($typeId);
	}
	function getWeekResultHtmlFromHot($typeId) {
		$datanalyse = $this->_getDatanalyseService();
		$result = $datanalyse->getDatanalyseForRateByType($typeId);
		if (!$result) {
			return '';
		}
		$tmp = array();
		foreach($result as $objectId => $object) {
			$info = array();
			$info['title'] = $object['title'];
			$info['href'] = "/" . $object['url'];
			$info['author'] = $object['author'];
			$info['authorUrl'] = "/u.php?username=" . $object['author'];
			$optionId = substr($object['action'], strrpos($object['action'], "_") + 1);
			$info['objectid'] = $objectId;
			$info['optionid'] = $optionId;
			$info['typeid'] = $typeId;
			$tmp[$optionId]['objectInfo'] = $info;
		}
		return $tmp;
	}
	function _getDatanalyseService() {
		L::loadClass('datanalyse','datanalyse',false);
		return new Datanalyse();
	}
	/***********************************************************/
	function _getRateConfigDB() {
		return L::loadDB('RateConfig', 'rate');
	}
	function _getRateDB() {
		return L::loadDB('Rate', 'rate');
	}
	function _getRateResultDB() {
		return L::loadDB('RateResult', 'rate');
	}
}
?>
