<?php if (!defined('VB_ENTRY')) die('Access denied.');
/*======================================================================*\
|| #################################################################### ||
|| # vBulletin 5.0.0 Beta 10
|| # ---------------------------------------------------------------- # ||
|| # Copyright 2000-2012 vBulletin Solutions Inc. All Rights Reserved. ||
|| # This file may not be redistributed in whole or significant part. # ||
|| # ---------------- VBULLETIN IS NOT FREE SOFTWARE ---------------- # ||
|| # http://www.vbulletin.com | http://www.vbulletin.com/license.html # ||
|| #################################################################### ||
\*======================================================================*/

/**
 * vB_Api_Socialgroup
 *
 * @package vBApi
 * @access public
 */
class vB_Api_SocialGroup extends vB_Api_Blog
{

	protected $sgChannel = false;
	protected $groups = array(
		'owner' => vB_Api_UserGroup::SG_OWNER_SYSGROUPID, 
		'mods' => vB_Api_UserGroup::SG_MODERATOR_SYSGROUPID,
		'members' => vB_Api_UserGroup::SG_MEMBER_SYSGROUPID
	);
	
	public function __construct()
	{
		parent::__construct();
	}

	/**
	 * @uses fetch the id of the global Blog Channel
	 * @return int nodeid of actual Main Blog Channel
	 */
	public function getSGChannel()
	{
		$options = vB::getDatastore()->getValue('options');
		if (isset($options['socialgroup_parentchannel']) AND !empty($options['socialgroup_parentchannel']))
		{
			$this->sgChannel = $options['socialgroup_parentchannel'];
		}
		else
		{
			// use default pagetemplate for blogs
			$this->sgChannel = vB::getDbAssertor()->getField('channel', array(
				vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_SELECT,
				vB_dB_Query::CONDITIONS_KEY => array('guid' => vB_Channel::DEFAULT_SOCIALGROUP_PARENT)
			));
		}

		if (empty($this->sgChannel))
		{
			throw new vB_Exception_Api('socialgroup_channel_not_set');
		}
		return $this->sgChannel;
	}

	/**
	 * Determines if the given node is a blog-related node (blog entry).
	 *
	 * @param	int	$nodeid
	 * @return	bool
	 */
	public function isSGNode($nodeId)
	{
		$nodeId = (int) $nodeId;

		if ($nodeId < 0)
		{
			return false;
		}

		$sgChannelId = (int) $this->getSGChannel();
		$nodeApi = vB_Api::instanceInternal('node');
		$node = $nodeApi->getNode($nodeId, true, false);

		return in_array($sgChannelId, $node['parents']);
	}
        
	/** gets Get info on every SG Channel
	 *
	 *	@param	array	Array of options to filter the info (used to show all/my groups). 
  	 * 	@return mixed 	array containing the blog channel info we need
	 */
	public function getSGInfo($options = array())
	{
		$response = array();
		$nodeApi = vB_Api::instanceInternal('node');
		
		$sgParentChannel = $this->getSGChannel();
		if (!empty($options['sgparent']) AND intval($options['sgparent']) AND (intval($options['sgparent'] != $sgParentChannel)))
		{
			$sgParent = intval($options['sgparent']);
			$depth = 1;
		}
		else
		{
			$sgParent = $sgParentChannel;
			$depth = 2;
		}

		// category check
		if (!$this->isSGNode($sgParent))
		{
			throw new vB_Exception_Api('invalid_sg_parent');
		}

		
		//Get base data
		$channelContentType  = vB_Types::instance()->getContentTypeId('vBForum_Channel');
		$params = array('starter_only' => 1, 'view' => 'activity');
		$queryParams = array('sgParentChannel' => $sgParent, 'depth' => $depth);
		if (!empty($options['userid']))
		{
			$queryParams['userid'] = $params['userid'] = intval($options['userid']);
		}
		
		$page = (!empty($options['page']) AND intval($options['page'])) ? intval($options['page']) : 1;
		$perpage = (!empty($options['perpage']) AND intval($options['perpage'])) ? intval($options['perpage']) : 20;
		$cacheParams = array_merge($params, array('page' => $page, 'perpage' => $perpage, 'sgparent' => $sgParent, 'depth' => $depth));
		$cacheKey = 'sgResults_' . (vB::getUserContext()->fetchUserId() ? vB::getUserContext()->fetchUserId() : 0) . crc32(serialize($cacheParams));
		
		if ($result = vB_Cache::instance(vB_Cache::CACHE_FAST)->read($cacheKey))
		{
			return $result;
		}
		else
		{
			$nodeContent = $nodeApi->listNodeContent($sgParent, $page, $perpage, $depth, $channelContentType, $params);
			$totalCount = vB::getDbAssertor()->getRow('vBForum:getSocialGroupsTotalCount', $queryParams);
	
			//We need the nodeids to collect some data
			$cacheEvents = array('nodeChg_' . $sgParent);
			$lastids = array();
			$channelids = array();
			$categories = array();
			$contributorIds = array();
			$sgCategories = array_keys($this->getCategories());
			$sgParentChannel = $this->getSGChannel();
			foreach ($nodeContent AS $key => $node)
			{
				if ($node['parentid'] == $sgParentChannel)
				{
					$categories[] = $node['nodeid'];
					unset($nodeContent[$node['nodeid']]);
				}
				else
				{
					if ($node['lastcontentid'] > 0)
					{
						$lastids[] = $node['lastcontentid'];
					}
					
					if (in_array($node['parentid'], $sgCategories))
					{
						$categories[] = $node['parentid'];
					}
					
					$channelids[] = $node['nodeid'];
					$contributorIds[] = $node['userid'];
					$cacheEvents[] = 'nodeChg_' . $node['nodeid'];
				}
			}
	
			$categories = array_unique($categories);
	
			if (empty($channelids))
			{
				$result =  array('results' => array(), 'totalcount' => 0, 'pageInfo' => array('currentpage' => $page, 'perpage' => $perpage, 'nexturl' => 0, 'prevurl' => 0, 'totalpages' => 0, 'totalrecords' => 0, 'sgparent' => $sgParent));
				vB_Cache::instance(vB_Cache::CACHE_FAST)->write($cacheKey, $result, 60, array_unique($cacheEvents));
				return $result;
			}
	
			$lastNodes = vB_Api::instanceInternal('node')->getNodes($lastids);
			$categoriesInfo = vB_Api::instanceInternal('node')->getNodes($categories);
	
			// update category info
			foreach ($nodeContent AS $key => $node)
			{
				// add category info
				if (isset($categoriesInfo[$node['parentid']]))
				{
					$nodeContent[$key]['content']['channeltitle'] = $categoriesInfo[$node['parentid']]['title'];
					$nodeContent[$key]['content']['channelroute'] = $categoriesInfo[$node['parentid']]['routeid'];
					$cacheEvents[] = 'nodeChg_' . $node['parentid'];
				}
			}
	
			$lastTitles = $lastInfo = array();
			foreach ($lastNodes as $lastnode)
			{
				$lastInfo[$lastnode['nodeid']]['title'] = $lastnode['title'];
				$lastInfo[$lastnode['nodeid']]['routeid'] = $lastnode['routeid'];
				$contributorIds[] = $lastnode['userid'];
			}
	
			//Get contributors
			$modGroupId = vB_Api::instanceInternal('usergroup')->getModeratorGroupId(vB_Api_UserGroup::SG_MODERATOR_SYSGROUPID);
			$memberGroupId = vB_Api::instanceInternal('usergroup')->getMemberGroupId(vB_Api_UserGroup::SG_MEMBER_SYSGROUPID);
			$ownerGroupId = vB_Api::instanceInternal('usergroup')->getOwnerGroupId(vB_Api_UserGroup::SG_OWNER_SYSGROUPID);
			$membersQry = vB::getDbAssertor()->getRows('vBForum:groupintopic', array(
				vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_SELECT,
				'nodeid' => $channelids,
				'groupid' => array($modGroupId, $memberGroupId, $ownerGroupId)
			));
			
			$groupManagers = array();
			foreach ($membersQry AS $record)
			{
				if ($record['groupid'] == $modGroupId)
				{
					$groupManagers[] = $record;
				}
				
				$cacheEvents[] = 'sgMemberChg_' . $record['userid'];
			}
			
			$contributors = array();
			$userApi = vB_Api::instanceInternal('user');
			foreach ($groupManagers as $index => $contributor)
			{
				if (!isset($contributors[$contributor['nodeid']]))
				{
					$contributors[$contributor['nodeid']] = array();
				}
				$contributorIds[] = $contributor['userid'];
			}
			$contributorIds = array_unique($contributorIds);
			
			$avatarInfo = vB_Api::instanceInternal('user')->fetchAvatars($contributorIds);
			foreach ($groupManagers as $index => $contributor)
			{
				if (!isset($contributors[$contributor['nodeid']]))
				{
					$contributors[$contributor['nodeid']] = array();
				}
				$userInfo = $userApi->fetchUserinfo($contributor['userid']);
				$contributors[$contributor['nodeid']][$contributor['userid']] = $userInfo;
				$contributors[$contributor['nodeid']][$contributor['userid']]['avatar'] = $avatarInfo[$contributor['userid']];
			}
			
			// Obtain keys for sg pages
			$pageKeyInfo = array();
			$routes = vB::getDbAssertor()->assertQuery('routenew', array('class' => 'vB5_Route_Channel', 'contentid' =>$channelids));
			foreach ($routes as $record)
			{
				$route = vB5_Route_Channel::getRoute($record['routeid'], @unserialize($record['arguments']));
				if ($route AND ($pageKey = $route->getPageKey()))
				{
					$pageKeyInfo[$pageKey] = $record['contentid'];
				}
			}
		
			$viewingQry = vB::getDbAssertor()->getRows('session',
				array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_SELECT, 'pagekey' => array_keys($pageKeyInfo))
			);
			
			$viewing = array();
			
			foreach ($viewingQry as $viewingUser)
			{
				if (!isset($viewing[$viewingUser['nodeid']]))
				{
					$viewing[$viewingUser['nodeid']] = 0;
				}
				$viewing[$viewingUser['nodeid']]++;
			}
	
			// get the members count
			$countRecords = vB::getDbAssertor()->assertQuery('vBForum:getSocialGroupMembersCount', array(
				'nodeid' => $channelids,
				'groupid' => array($ownerGroupId, $modGroupId, $memberGroupId)
			));
			
			$membersCount = array();
			foreach ($countRecords AS $count)
			{
				$membersCount[$count['nodeid']] = $count;
			}
	
			foreach ($nodeContent AS $index => $channel)
			{
				$nodeid = $channel['nodeid'];
				$nodeContent[$index]['contributors'] = !empty($contributors[$nodeid]) ? $contributors[$nodeid] : 0;
				$nodeContent[$index]['contributorscount'] = !empty($contributors[$nodeid]) ? count($contributors[$nodeid]) : 0;
				$nodeContent[$index]['members'] = !empty($membersCount[$nodeid]) ? $membersCount[$nodeid]['members'] : 0;
				$nodeContent[$index]['viewing'] = !empty($viewing[$nodeid]) ? $viewing[$nodeid] : 0 ;
				$nodeContent[$index]['lastposttitle'] = !empty($lastInfo[$channel['lastcontentid']]['title']) ? $lastInfo[$channel['lastcontentid']]['title'] : 0;
				$nodeContent[$index]['lastpostrouteid'] = !empty($lastInfo[$channel['lastcontentid']]['routeid']) ? $lastInfo[$channel['lastcontentid']]['routeid'] : 0;
				
				$nodeContent[$index]['owner_avatar'] = $avatarInfo[$nodeContent[$index]['userid']];
				$nodeContent[$index]['lastauthor_avatar'] = $avatarInfo[$nodeContent[$index]['lastauthorid']];
			}
	
			$total = $totalCount['totalcount'];
			$pages = ceil($total/$perpage);
			$nextPage = ($page < $pages) ? ($page + 1) : 0;
			$prevPage = ($page - 1) >= 1 ? ($page - 1) : 0;

			$result =  array('results' => $nodeContent, 'totalcount' => count($nodeContent), 'pageInfo' => array('currentpage' => $page, 'perpage' => $perpage, 'nexturl' => $nextPage, 'prevurl' => $prevPage, 'totalpages' => $pages, 'totalrecords' => $total, 'sgparent' => $sgParent));
			vB_Cache::instance(vB_Cache::CACHE_FAST)->write($cacheKey, $result, 60, array_unique($cacheEvents));
			
			return $result; 
		}
	}


	/** get the current user's admin permissions
	*
	*   nodeid to check
	*	@param  int		the
  	*	@return	array of canadmin, canmoderate
	*/
	public function getSGAdminPerms($nodeid)
	{
		$userContext = vB::getUserContext();

		if ($userContext->getChannelPermission('moderatorpermissions', 'canaddowners', $nodeid))
		{
			return array('canadmin' => 1, 'canmoderate' => 1);
		}
		else if ($userContext->getChannelPermission('moderatorpermissions', 'canmoderateposts', $nodeid))
		{
			return array('canadmin' => 0, 'canmoderate' => 1);
		}
		else
		{
			return array('canadmin' => 0, 'canmoderate' => 0);
		}
	}

	/** returns the category list- direct children of the social group channel
	 *
	 *  @return mixed   array of nodeid => title
	 */
	public function getCategories()
	{
		$sgChannel = $this->getSGChannel();
		$categories = vB::getDbAssertor()->assertQuery('vBForum:node', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_SELECT,
			'parentid' => $sgChannel, 'contenttypeid' => vB_Types::instance()->getContentTypeID('vBForum_Channel')),
			'title');
		$return = array();
		$userContext = vB::getUserContext();
		foreach ($categories as $category)
		{
			if ($userContext->getChannelPermission( 'forumpermissions', 'canview', $category['nodeid'], false, $sgChannel))
			{
				$return[$category['nodeid']] = array(
					'title' => $category['title'],
					'routeid' => $category['routeid'],
					'content' => $category['content'],
				);
			}
		}
		return $return;
	}

	/** creates a new social group
	 *
	 *  @param  mixed   array which must include parentid, title. Should also have various options and a description.
	 *
	 *  @return int nodeid of the created group/channel
	 */
	public function createSocialGroup($input)
	{
        if (empty($input['parentid']))
		{
        	throw new vB_Exception_Api('invalid_sg_parent');   
        }
		$sgParent = intval($input['parentid']);
        $catNode = vB_Api::instanceInternal('node')->getNode($sgParent);

		if (empty($catNode) OR $catNode['parentid'] != $this->getSGChannel())
		{
			throw new vB_Exception_Api('invalid_sg_parent');
		}
		
		// social group type, we allow post by default while creating social group
		$input['nodeoptions'] = 2;
		switch ($input['group_type'])
		{
			case 2:
				$input['nodeoptions'] |= vB_Api_Node::OPTION_NODE_INVITEONLY;
				break;
			case 1:
				break;
			default:
				$input['nodeoptions'] |= vB_Api_Node::OPTION_AUTOAPPROVE_MEMBERSHIP;
				break;
		}
		
		return $this->createPost($input, $sgParent, vB_Page::getSGConversPageTemplate(), vB_Page::getSGChannelPageTemplate(), vB_Api_UserGroup::SG_OWNER_SYSGROUPID);
	}

	/** lists group members
	 *
	 *  @param  int		nodeid of the group to be checked
	 *
	 *  @return mixed	array of userid,  username.
	 */
	public function fetchMembers($nodeid, $pageno = 1, $perpage = 20, $thumb = false)
	{
		if (!$nodeid OR !(intval($nodeid) > 0) OR !$pageno OR !(intval($pageno) > 0) OR
			!$perpage OR !(intval($perpage) > 0))
		{
			throw new vB_Exception_Api('invalid_data');
		}
		$userContext = vB::getUserContext();

		if (!$userContext->getChannelPermission('moderatorpermissions', 'canmoderateposts', $nodeid))
		{
			throw new vB_Exception_Api('no_permission');
		}
		$assertor = vB::getDbAssertor();
		$pageno = max($pageno, 1);
		$group = vB_Api::instanceInternal('usergroup')->fetchUsergroupBySystemID(vB_Api_UserGroup::SG_MEMBER_SYSGROUPID);
		$memberQry = $assertor->assertQuery('vBForum:groupintopicPage', array(vB_dB_Query::PARAM_LIMIT => $perpage,
		vB_dB_Query::PARAM_LIMITSTART => $perpage * ($pageno - 1), 'nodeid' => $nodeid, 'groupid' => $group['usergroupid']));

		$members = array();
		foreach ($memberQry as $member)
		{
			$members[$member['userid']] = array();
		}

		$userApi = vB_Api::instanceInternal('user');

		if (empty($members))
		{
			return array('count' => 0, 'members' => array(), 'pagecount' => 1);

		}
		$userQry = $assertor->assertQuery('user', array(vB_dB_Query::QUERY_SELECT,
			'userid' => array_keys($members)));
		foreach ($userQry as $user)
		{
			$avatarUrl = $userApi->fetchAvatar($user['userid'], $thumb, $user);
			if (empty($avatarUrl))
			{
				$user['avatarUrl'] = 0;
			}
			else
			{
				$user['avatarUrl'] = $avatarUrl['avatarpath'];
			}
			$members[$user['userid']]= array('userid' => $user['userid'],
				'username' => $user['username'], 'avatarUrl' => $user['avatarUrl'], 'groupid' => $group['usergroupid']);
		}
		$count = $assertor->getRow('vBForum:groupintopicCount', array('groupid' => $group['usergroupid'], 'nodeid' => $nodeid));
		$count = $count['count'];
		$pagecount = ceil($count/$perpage);
		return array('count' => $count, 'members' => $members, 'pagecount' => $count);

	}

	/** Remove someone as a subs
	 * @param $userid
	 * @param $nodeid
	 *
	 *
	 */
	public function removeSubscriber($userid, $nodeid)
	{
		//make sure we have valid data.
		if (!intval($userid) OR !intval($nodeid))
		{
			throw new vB_Exception_Api('invalid_data');
		}

		//first check permissions
		//user can always delete their own subscription
		if ($userid != vB::getCurrentSession()->get('userid'))
		{
			$userContext = vB::getUserContext();
			if (!$userContext->getChannelPermission('moderatorpermissions', 'canmoderateposts', $nodeid))
			{
				throw new vB_Exception_Api('no_permission');
			}
		}

		return vB::getDbAssertor()->assertQuery('subscribediscussion', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_DELETE,
			'userid' => $userid, 'discussionid' => $nodeid));

	}
	
	/** creates a new category
	 *
	 *	@param	int
	 *  @param  mixed   array which must include title and optionally parentid
	 *
	 *  @return int nodeid of the created category
	 */
	public function saveCategory($nodeId, $input)
	{
		$channelApi = vB_Api::instanceInternal('content_channel');
		
		$nodeId = (int) $nodeId;
		
		// force social group channel as parent id (categories cannot be nested)
		$input['parentid'] = $this->getSGChannel();
		$input['category'] = 1; // force channel to be a category
		$input['templates']['vB5_Route_Channel'] = vB_Page::getSGCategoryPageTemplate();
		$input['templates']['vB5_Route_Conversation'] = vB_Page::getSGCategoryConversPageTemplate();
		
		// TODO: this code is similar to vB_Api_Widget::saveChannel, add a library method with it?
		if ($nodeId > 0)
		{
			// this call won't update parentid
			$channelApi->update($nodeId, $input);
		}
		else
		{
			$nodeId = $channelApi->add($input);
		}
		
		return $nodeId;
	}
}

/*======================================================================*\
|| ####################################################################
|| # 
|| # SVN: $Revision$
|| ####################################################################
\*======================================================================*/
