<?php

    /**
	 * \ingroup DAO
	 *
     * Model for the friends feature
     */
    class Friends extends Model
	{

		function Friends()
		{
			$this->Model();

			$this->table = $this->getPrefix()."friends";
		}

        /**
		 * Retrieves the friends of the given user.
         *
         * @param userId Identifier of the user
         * @param groupId Group identifier of the friends
         * @param userAuthorizationStatus User authorization status
         * @param friendAuthorizationStatus Friend authorization status
		 * @param searchTerms
		 * @param page
		 * @param itemsPerPage
		 */
		function getFriends( $userId, $groupId = 0, $userAuthorizationStatus = USER_AUTHORIZATION_ALL, $friendAuthorizationStatus = FRIEND_AUTHORIZATION_ALL, $searchTerms = "", $page = -1, $itemsPerPage = 15 )
		{
			$friends = Array();
			$query = "SELECT id FROM ".$this->getPrefix()."friends WHERE user_id = '".$userId."' AND";
			if( $groupId != 0 )
				$query .= " group_id = '".LtDb::qstr($groupId)."' AND";
			if( $userAuthorizationStatus != USER_AUTHORIZATION_ALL )
				$query .= " user_authorization_status = '".LtDb::qstr($userAuthorizationStatus)."' AND";
			if( $friendAuthorizationStatus != FRIEND_AUTHORIZATION_ALL )
				$query .= " friend_authorization_status = '".LtDb::qstr($friendAuthorizationStatus)."' AND";
			if( $searchTerms != "" )
				$query .= " (".$this->getSearchConditions( $searchTerms ).")";

			// just in case if for any reason the string ends with "AND"
			$query = trim( $query );
			if( substr( $query, -3, 3 ) == "AND" )
				$query = substr( $query, 0, strlen( $query ) - 3 );

			$result = $this->Execute( $query, $page, $itemsPerPage );
			if( !$result )
				return $friends;

			while( $row = $result->FetchRow()) {
				// use the primary key to retrieve the items via the cache
				$friends[] = $this->get( "id", $row["id"], DaoCacheConstants::CACHE_FRIENDS );
			}

            return $friends;
		}

		/**
		 * returns how many friend a user has
		 *
		 * @param userId
		 * @param groupId
		 * @param searchTerms
		 * @return an integer
		 */
		function getNumFriends( $userId, $groupId = 0, $userAuthorizationStatus = USER_AUTHORIZATION_ALL, $friendAuthorizationStatus = FRIEND_AUTHORIZATION_ALL, $searchTerms = "" )
		{
			return( count( $this->getFriends( $userId, $groupId, $userAuthorizationStatus, $friendAuthorizationStatus, $searchTerms )));
		}

		function isFriend( &$friend )
		{
			return $this->getNumItems( $this->getPrefix().'friends', 'user_id = '.$friend->getUserId().' AND friend_id = '.$friend->getFriendId() );
		}

		/**
		 * Updates friend group counters
		 *
		 * @private
		 */
		function updateFriendGroupCounters( $newFriend, $oldFriend = null )
		{
			
			$groups = new FriendGroups();
			$newGroup = $groups->getFriendGroup( $newFriend->getGroupId() );

			if( $newGroup ) {
				$newGroup->setNumFriends($this->getNumItems( $this->getPrefix().'friends', 'group_id = '.$newGroup->getId()));
				$newGroup->setNumAuthorizedFriends($this->getNumItems( $this->getPrefix().'friends', 'group_id = '.$newGroup->getId().' AND user_authorization_status = '.USER_AUTHORIZATION_CONFIRMED.' AND friend_authorization_status = '.FRIEND_AUTHORIZATION_CONFIRMED ));
				$newGroup->setNumWaitingFriends($this->getNumItems( $this->getPrefix().'friends', 'group_id = '.$newGroup->getId().' AND user_authorization_status = '.USER_AUTHORIZATION_WAITING.' AND friend_authorization_status = '.FRIEND_AUTHORIZATION_CONFIRMED ));
				$newGroup->setNumPendingFriends($this->getNumItems( $this->getPrefix().'friends', 'group_id = '.$newGroup->getId().' AND user_authorization_status = '.USER_AUTHORIZATION_CONFIRMED.' AND friend_authorization_status = '.FRIEND_AUTHORIZATION_WAITING ));
				$groups->updateFriendGroup( $newGroup );
			}

			if( $oldFriend ) {
				$oldGroup = $groups->getFriendGroup( $oldFriend->getGroupId() );
				if ($oldGroup)
				{
					$oldGroup->setNumFriends($this->getNumItems( $this->getPrefix().'friends', 'group_id = '.$oldGroup->getId()));
					$oldGroup->setNumAuthorizedFriends($this->getNumItems( $this->getPrefix().'friends', 'group_id = '.$oldGroup->getId().' AND user_authorization_status = '.USER_AUTHORIZATION_CONFIRMED.' AND friend_authorization_status = '.FRIEND_AUTHORIZATION_CONFIRMED ));
					$oldGroup->setNumWaitingFriends($this->getNumItems( $this->getPrefix().'friends', 'group_id = '.$oldGroup->getId().' AND user_authorization_status = '.USER_AUTHORIZATION_WAITING.' AND friend_authorization_status = '.FRIEND_AUTHORIZATION_CONFIRMED ));
					$oldGroup->setNumPendingFriends($this->getNumItems( $this->getPrefix().'friends', 'group_id = '.$oldGroup->getId().' AND user_authorization_status = '.USER_AUTHORIZATION_CONFIRMED.' AND friend_authorization_status = '.FRIEND_AUTHORIZATION_WAITING ));
					$groups->updateFriendGroup( $oldGroup );
				}
			}

			return( true );
		}

        /**
         * Adds a friend to the database
         *
         * @param friend a Friend object
         * @return True if successful or false otherwise.
         */
        function addFriend( &$friend )
        {
        	if( $this->isFriend( $friend ) )
        		return false;

        	$result = $this->add( $friend );

			if( $result ) {
				// clean the cache
                $this->_cache->removeData( $friend->getId(), DaoCacheConstants::CACHE_FRIENDS );
				// update the friend group counters
				$this->updateFriendGroupCounters( $friend );
			}

            return $result;
        }

        /**
         * Removes a Friend object from the database.
         *
         * @param friendId The friend identifier.
         * @param userId The user identifier.
         * @return True if successful or false otherwise.
         */
        function deleteFriend( $id, $userId )
        {
        	$friend = $this->getFriend( $id, $userId );
        	if( $friend ) {
        		$this->delete( "id", $id );
	            $this->_cache->removeData( $id, DaoCacheConstants::CACHE_FRIENDS );
				// update friend realtionship counters
				$this->updateFriendGroupCounters( $friend );

				return( true );
        	}
        	else
        		return false;
        }

        /**
         * Removes a Friend object from the database.
         *
         * @param friendId The friend identifier.
         * @param userId The user identifier.
         * @return True if successful or false otherwise.
         */
        function deleteFriendByUserIdAndFriendId( $userId, $friendId )
        {
        	$friends = $this->getFriends( $userId );
        	foreach( $friends as $friend ) {
	        	if( $friend->getFriendId() == $friendId ) {
	        		$id = $friend->getId();
	        		$this->delete( "id", $id );
		            $this->_cache->removeData( $id, DaoCacheConstants::CACHE_FRIENDS );
					// update friend realtionship counters
					$this->updateFriendGroupCounters( $friend );

					return( true );
	        	}
        	}

       		return false;
        }

        /**
         * Removes all the friends from the given user identifier
         *
         * @param userId The blog identifier
         */
        function deleteUserFriends( $userId )
        {
        	$friends = $this->getFriends( $userId );

        	if( $this->delete( "user_id", $userId )) {
        		if( !$friends ) {
        			return false;
        		}
	        	foreach ( $friends as $friend ) {
					$this->_cache->removeData( $friends->getId(), DaoCacheConstants::CACHE_FRIENDS );
	        	}
	        	return true;
        	}
        	else
        		return false;
        }

        /**
         * Removes all the friends from the given friendId
         *
         * @param friendId The friend identifier
         */
        function deleteAllUsersFriendsByFriendId( $friendId )
        {
        	$friends = $this->_getAllUsersFriendsByFriendId( $friendId );

        	if( $this->delete( "friend_id", $friendId )) {
	        	foreach ( $friends as $friend ) {
					$this->_cache->removeData( $friends->getId(), DaoCacheConstants::CACHE_FRIENDS );
	        	}
	        	return true;
        	}
        	else
        		return false;
        }

        /**
		 * Retrieves the friends of the given friend identifier. This method only
		 * used in $this->deleteAllUsersFriendsByFriendId()
         *
         * @param friendId Identifier of the user
		 */
		function _getAllUsersFriendsByFriendId( $friendId )
		{
			$friends = Array();
			$query = "SELECT id FROM ".$this->table." WHERE friend_id = '".$friendId;

			$result = $this->Execute( $query );
			if( !$result )
				return $friends;

			while( $row = $result->FetchRow()) {
				// use the primary key to retrieve the items via the cache
				$friends[] = $this->get( "id", $row["id"], DaoCacheConstants::CACHE_FRIENDS );
			}

            return $friends;
		}

        /**
         * Retrieves a single friend object from db.
         *
         * @param id The identifier
         * @param userId The user identifier
         * @return The Friend object containing information or false if it didn't exist
         */
        function getFriend( $id, $userId = -1 )
        {
        	$friend = $this->get( "id", $id, DaoCacheConstants::CACHE_FRIENDS );
        	if( !$friend )
        		return false;

			if( $userId == -1 )
				return $friend;

			if( $friend->getUserId() == $userId )
				return $friend;
			else
				return false;
        }

        /**
         * Removes a Friend object from the database.
         *
         * @param friendId The friend identifier.
         * @param userId The user identifier.
         * @return True if successful or false otherwise.
         */
        function getFriendByUserIdAndFriendId( $userId, $friendId )
        {
        	$friends = $this->getFriends( $userId );
        	foreach( $friends as $friend ) {
	        	if( $friend->getFriendId() == $friendId ) {
					return $friend;
	        	}
        	}

       		return false;
        }

        /**
         * Updates a friend in the database.
         *
         * @param friend A Friend object with the information we'd like to update.
         * @return True if successful or false otherwise.
         */
        function updateFriend( &$friend )
        {
			// get the previous version of this friend before saving it
			$prevVersion = $this->getFriend( $friend->getId());

        	$result = $this->update( $friend );

            if( !$result ) {
            	return false;
            }

			// clean the cache
            $this->_cache->removeData( $friend->getId(), DaoCacheConstants::CACHE_FRIENDS );

			// update friend realtionship counters
			$this->updateFriendGroupCounters( $friend, $prevVersion );

          	return true;
        }

		/**
		 * @see Model::getSearchConditions
		 */
		function getSearchConditions( $searchTerms )
		{
			return( "(description LIKE '%".LtDb::qstr( $searchTerms )."%')" );
		}

		/**
		 * @private
		 */
        function mapRow( $row )
        {
            $friend = new Friend( $row["user_id"],
                                  $row["friend_id"],
			                      $row["group_id"],
			                      $row["description"],
			                      $row["user_authorization_status"],
			                      $row["friend_authorization_status"],
								  $row["id"] );

			return $friend;

        }
    }
?>
