<?php
/**
 * @brief		Support Replies API
 * @author		<a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
 * @copyright	(c) Invision Power Services, Inc.
 * @license		https://www.invisioncommunity.com/legal/standards/
 * @package		Invision Community
 * @subpackage	Nexus
 * @since		11 Dec 2015
 */

namespace IPS\nexus\api;

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
	header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
	exit;
}

/**
 * @brief	Support Replies API
 */
class _supportreplies extends \IPS\Content\Api\CommentController
{
	/**
	 * Class
	 */
	protected $class = 'IPS\nexus\Support\Reply';
	
	/**
	 * GET /nexus/supportreplies
	 * Get list of support replies
	 *
	 * @note		For requests using an OAuth Access Token for a particular member, only topics the authorized user can view will be included - if the user is a staff member, will use their staff permissions
	 * @apiparam	int		staffReplies	If 1, only replies by staff will be included. If 0, only replies by non-staff.
	 * @apiparam	string	authors			Comma-delimited list of member IDs - if provided, only replies by those members are returned
	 * @apiparam	string	departments		Comma-delimited list of department IDs
	 * @apiparam	string	statuses		Comma-delimited list of status IDs
	 * @apiparam	string	severities		Comma-delimited list of severity IDs
	 * @apiparam	string	sortBy			What to sort by. Can be 'date', 'title' or leave unspecified for ID
	 * @apiparam	string	sortDir			Sort direction. Can be 'asc' or 'desc' - defaults to 'asc'
	 * @apiparam	int		page			Page number
	 * @apiparam	int		perPage			Number of results per page - defaults to 25
	 * @return		\IPS\Api\PaginatedResponse<IPS\nexus\Support\Reply>
	 */
	public function GETindex()
	{
		/* Init */
		$where = array();
		
		/* Type */
		if ( isset( \IPS\Request::i()->staffReplies ) )
		{
			$where[] = array( \IPS\Db::i()->in( 'reply_type', \IPS\Request::i()->staffReplies ? array( \IPS\nexus\Support\Reply::REPLY_STAFF, \IPS\nexus\Support\Reply::REPLY_HIDDEN ) : array( \IPS\nexus\Support\Reply::REPLY_MEMBER, \IPS\nexus\Support\Reply::REPLY_ALTCONTACT, \IPS\nexus\Support\Reply::REPLY_EMAIL ) ) );
		}
		else
		{
			$where[] = array( 'reply_type<>?', \IPS\nexus\Support\Reply::REPLY_PENDING );
		}
		
		/* Departments */
		if ( isset( \IPS\Request::i()->departments ) )
		{
			$where[] = array( \IPS\Db::i()->in( 'r_department', array_map( 'intval', array_filter( explode( ',', \IPS\Request::i()->departments ) ) ) ) );
		}
		
		/* Statuses */
		if ( isset( \IPS\Request::i()->statuses ) )
		{
			$where[] = array( \IPS\Db::i()->in( 'r_status', array_map( 'intval', array_filter( explode( ',', \IPS\Request::i()->statuses ) ) ) ) );
		}

		/* Severities */
		if ( isset( \IPS\Request::i()->severities ) )
		{
			$where[] = array( \IPS\Db::i()->in( 'r_severity', array_map( 'intval', array_filter( explode( ',', \IPS\Request::i()->statuses ) ) ) ) );
		}
		
		/* Are we a staff member? */
		$bypassPerms = FALSE;
		if ( $this->member and $this->member->isAdmin() and \count( \IPS\nexus\Support\Department::departmentsWithPermission( $this->member ) ) )
		{
			$where[] = array( \IPS\Db::i()->in( 'r_department', array_keys( iterator_to_array( \IPS\nexus\Support\Department::departmentsWithPermission( $this->member ) ) ) ) );
			$bypassPerms = TRUE;
		}

		/* Return */
		return $this->_list( $where, NULL, $bypassPerms );
	}
	
	/**
	 * GET /nexus/supportreplies/{id}
	 * View information about a specific reply
	 *
	 * @param		int		$id			ID Number
	 * @throws		2X314/1	INVALID_ID	The reply ID does not exist or the authorized user does not have permission to view it
	 * @return		\IPS\nexus\Support\Reply
	 */
	public function GETitem( $id )
	{
		try
		{
			$class = $this->class;
			if ( $this->member )
			{
				$object = $class::loadAndCheckPerms( $id, $this->member );
			}
			else
			{
				$object = $class::load( $id );
			}
			
			return new \IPS\Api\Response( 200, $object->apiOutput( $this->member ) );
		}
		catch ( \OutOfRangeException $e )
		{
			throw new \IPS\Api\Exception( 'INVALID_ID', '2X314/1', 404 );
		}
	}
	
	/**
	 * POST /nexus/supportreplies
	 * Create a reply
	 *
	 * @reqapiparam	int			request				The ID number of the request the reply is for
	 * @reqapiparam	int			author				The ID number of the member making the post (0 for guest).  Required for requests made using an API Key or the Client Credentials Grant Type. For requests using an OAuth Access Token for a particular member, that member will always be the author.
	 * @reqapiparam	string		message				The reply content as HTML (e.g. "<p>This is a post.</p>"). Will be sanatized for requests using an OAuth Access Token for a particular member; will be saved unaltered for requests made using an API Key or the Client Credentials Grant Type. 
	 * @apiparam	datetime	date				The date/time that should be used for the topic/post post date. If not provided, will use the current date/time. Ignored for requests using an OAuth Access Token for a particular member
	 * @apiparam	string		ip_address			The IP address that should be stored for the topic/post. If not provided, will use the IP address from the API request. Ignored for requests using an OAuth Access Token for a particular member
	 * @apiparam	bool		hidden				If true will be added as a hidden note. Ignored if authorized member is not staff
	 * @throws		2X314/2		NO_REQUEST		The support request ID does not exist or the authorized user does not have permission to access it
	 * @throws		1X314/3		NO_AUTHOR		The author ID does not exist
	 * @throws		1X314/4		NO_MESSAGE		No message was supplied
	 * @return		\IPS\nexus\Support\Reply
	 */
	public function POSTindex()
	{
		/* Get request */
		try
		{
			$request = \IPS\nexus\Support\Request::load( \IPS\Request::i()->request );
			if ( $this->member )
			{
				if ( $request->canView( $this->member ) )
				{
					// Okay
				} 
				elseif ( $this->member->isAdmin() and ( $request->department->staff === '*' or \count( array_intersect( explode( ',', $request->department->staff ), Department::staffDepartmentPerms( $this->member ) ) ) ) )
				{
					// Okay
				}
				else
				{
					throw new \OutOfRangeException;
				}
			}
		}
		catch ( \OutOfRangeException $e )
		{
			throw new \IPS\Api\Exception( 'NO_REQUEST', '2X314/2', 403 );
		}
		
		/* Get author */
		if ( $this->member )
		{
			$author = $this->member;
		}
		else
		{
			if ( \IPS\Request::i()->author )
			{
				$author = \IPS\Member::load( \IPS\Request::i()->author );
				if ( !$author->member_id )
				{
					throw new \IPS\Api\Exception( 'NO_AUTHOR', '1X314/3', 403 );
				}
			}
			else
			{
				$author = new \IPS\Member;
				$author->name = \IPS\Request::i()->author_name;
			}
		}
		
		/* Check we have a post */
		if ( !\IPS\Request::i()->message )
		{
			throw new \IPS\Api\Exception( 'NO_MESSAGE', '1X314/4', 403 );
		}
		
		/* Do it */
		return $this->_create( $request, $author, 'message' );
	}
	
	/**
	 * Create
	 *
	 * @param	\IPS\Content\Item	$item			Content Item
	 * @param	\IPS\Member			$author			Author
	 * @param	string				$contentParam	The parameter that contains the content body
	 * @return	\IPS\Api\Response
	 */
	protected function _createComment( \IPS\Content\Item $item, \IPS\Member $author, $contentParam='content' )
	{
		$comment = parent::_createComment( $item, $author, $contentParam );
		if ( $this->member )
		{
			if ( !$item->canView( $this->member ) )
			{
				$comment->type = $comment::REPLY_STAFF;
				if ( \IPS\Request::i()->hidden )
				{
					$comment->type = $comment::REPLY_HIDDEN;
				}
			}
		}
		$comment->save();
		return $comment;
	}
	
	/**
	 * POST /nexus/supportreplies/{id}
	 * Edit a reply
	 *
	 * @apiclientonly
	 * @param		int			$id			ID Number
	 * @apiparam	int			author		The ID number of the member making the post (0 for guest)
	 * @apiparam	string		message		The post content as HTML (e.g. "<p>This is a post.</p>")
	 * @throws		2X314/5		INVALID_ID	The post ID does not exist
	 * @throws		1X314/6		NO_AUTHOR	The author ID does not exist
	 * @return		\IPS\forums\Topic\Post
	 */
	public function POSTitem( $id )
	{
		try
		{
			/* Load */
			$post = \IPS\nexus\Support\Reply::load( $id );
			
			/* Do it */
			try
			{
				return $this->_edit( $post, 'message' );
			}
			catch ( \InvalidArgumentException $e )
			{
				throw new \IPS\Api\Exception( 'NO_AUTHOR', '1X314/6', 400 );
			}
		}
		catch ( \OutOfRangeException $e )
		{
			throw new \IPS\Api\Exception( 'INVALID_ID', '2X314/5', 404 );
		}
	}
		
	/**
	 * DELETE /nexus/supportreplies/{id}
	 * Deletes a reply
	 *
	 * @apiclientonly
	 * @param		int			$id							ID Number
	 * @throws		2X314/7		INVALID_ID					The post ID does not exist
	 * @throws		1X314/8		CANNOT_DELETE_FIRST_POST	You cannot delete the first reply to a request. Delete the request itself instead.
	 * @return		void
	 */
	public function DELETEitem( $id )
	{
		try
		{
			$reply = \IPS\nexus\Support\Reply::load( $id );
			
			if ( $reply->isFirst() )
			{
				throw new \IPS\Api\Exception( 'CANNOT_DELETE_FIRST_POST', '1X314/8', 403 );
			}
			
			$reply->delete();
			
			return new \IPS\Api\Response( 200, NULL );
		}
		catch ( \OutOfRangeException $e )
		{
			throw new \IPS\Api\Exception( 'INVALID_ID', '2X314/7', 404 );
		}
	}
}