/*
 * Asterisk -- An open source telephony toolkit.
 *
 * Copyright (C) 2013, Digium, Inc.
 *
 * Jonathan Rose <jrose@digium.com>
 *
 * See http://www.asterisk.org for more information about
 * the Asterisk project. Please do not directly contact
 * any of the maintainers of this project for assistance;
 * the project provides a web site, mailing lists and IRC
 * channels for your use.
 *
 * This program is free software, distributed under the terms of
 * the GNU General Public License Version 2. See the LICENSE file
 * at the top of the source tree.
 */

/*! \file
 *
 * \brief Call Parking API
 *
 * \author Jonathan Rose <jrose@digium.com>
 */

#include "asterisk/stringfields.h"
#include "asterisk/bridge.h"

/*!
 * \brief The default parking application that Asterisk expects.
 */
#define PARK_APPLICATION "Park"

/*!
 * \brief The default parking lot
 */
#define DEFAULT_PARKINGLOT "default"

/*!
 * \brief Defines the type of parked call message being published
 * \since 12
 */
enum ast_parked_call_event_type {
	PARKED_CALL = 0,
	PARKED_CALL_TIMEOUT,
	PARKED_CALL_GIVEUP,
	PARKED_CALL_UNPARKED,
	PARKED_CALL_FAILED,
	PARKED_CALL_SWAP,
};

/*!
 * \brief A parked call message payload
 * \since 12
 */
struct ast_parked_call_payload {
	struct ast_channel_snapshot *parkee;             /*!< Snapshot of the channel that is parked */
	struct ast_channel_snapshot *retriever;          /*!< Snapshot of the channel that retrieved the call (may be NULL) */
	enum ast_parked_call_event_type event_type;      /*!< Reason for issuing the parked call message */
	long unsigned int timeout;                       /*!< Time remaining before the call times out (seconds ) */
	long unsigned int duration;                      /*!< How long the parkee has been parked (seconds) */
	unsigned int parkingspace;                       /*!< Which Parking Space the parkee occupies */
	AST_DECLARE_STRING_FIELDS(
		AST_STRING_FIELD(parkinglot);                /*!< Name of the parking lot used to park the parkee */
		AST_STRING_FIELD(parker_dial_string);          /*!< The device string used for call control on parking timeout */
	);
};

struct ast_exten;

/*!
 * \brief Constructor for parked_call_payload objects
 * \since 12
 *
 * \param event_type What kind of parked call event is happening
 * \param parkee_snapshot channel snapshot of the parkee
 * \param parker_dial_string dialstring used when the call times out
 * \param retriever_snapshot channel snapshot of the retriever (NULL allowed)
 * \param parkinglot name of the parking lot where the parked call is parked
 * \param parkingspace what numerical parking space the parked call is parked in
 * \param timeout how long the parked call can remain at the point this snapshot is created before timing out
 * \param duration how long the parked call has currently been parked
 *
 * \retval NULL if the parked call payload can't be allocated
 * \retval reference to a newly created parked call payload
 */
struct ast_parked_call_payload *ast_parked_call_payload_create(enum ast_parked_call_event_type event_type,
		struct ast_channel_snapshot *parkee_snapshot, const char *parker_dial_string,
		struct ast_channel_snapshot *retriever_snapshot, const char *parkinglot,
		unsigned int parkingspace, unsigned long int timeout, unsigned long int duration);

/*! \addtogroup StasisTopicsAndMessages
 * @{
 */

/*!
 * \brief accessor for the parking stasis topic
 * \since 12
 *
 * \retval NULL if the parking topic hasn't been created or has been disabled
 * \retval a pointer to the parking topic
 */
struct stasis_topic *ast_parking_topic(void);

/*!
 * \brief accessor for the parked call stasis message type
 * \since 12
 *
 * \retval NULL if the parking topic hasn't been created or has been canceled
 * \retval a pointer to the parked call message type
 */
struct stasis_message_type *ast_parked_call_type(void);

/*! @} */

#define PARKING_MODULE_VERSION 1

struct ast_module_info;

/*!
 * \brief A function table providing parking functionality to the \ref AstBridging
 * Bridging API and other consumers
 */
struct ast_parking_bridge_feature_fn_table {

	/*!
	 * \brief The version of this function table. If the ABI for this table
	 * changes, the module version (/ref PARKING_MODULE_VERSION) should be
	 * incremented.
	 */
	unsigned int module_version;

	/*!
	 * \brief The name of the module that provides this parking functionality
	 */
	const char *module_name;

	/*!
	 * \brief Determine if the context/exten is a "parking" extension
	 *
	 * \retval 0 if the extension is not a parking extension
	 * \retval 1 if the extension is a parking extension
	 */
	int (* parking_is_exten_park)(const char *context, const char *exten);

	/*!
	 * \brief Park the bridge and/or callers that this channel is in
	 *
	 * \param parker The bridge_channel parking the bridge
	 * \param exten Optional. The extension the channel or bridge was parked at if the
	 * call succeeds.
	 * \param length Optional. If \c exten is specified, the size of the buffer.
	 *
	 * \note This is safe to be called outside of the \ref AstBridging Bridging API.
	 *
	 * \retval 0 on success
	 * \retval non-zero on error
	 */
	int (* parking_park_call)(struct ast_bridge_channel *parker, char *exten, size_t length);

	/*!
	 * \brief Perform a blind transfer to a parking extension.
	 *
	 * \param parker The \ref bridge_channel object that is initiating the parking
	 * \param context The context to blind transfer to
	 * \param exten The extension to blind transfer to
	 * \param parked_channel_cb Execute the following function on the channel that gets parked
	 * \param parked_channel_data Data for the parked_channel_cb
	 *
	 * \note If the bridge \ref parker is in has more than one other occupant, the entire
	 * bridge will be parked using a Local channel
	 *
	 * \note This is safe to be called outside of the \ref AstBridging Bridging API.
	 *
	 * \retval 0 on success
	 * \retval non-zero on error
	 */
	int (* parking_blind_transfer_park)(struct ast_bridge_channel *parker, const char *context,
		const char *exten, transfer_channel_cb parked_channel_cb, struct transfer_channel_data *parked_channel_data);

	/*!
	 * \brief Perform a direct park on a channel in a bridge.
	 *
	 * \param parkee The channel in the bridge to be parked.
	 * \param parkee_uuid The UUID of the channel being packed.
	 * \param parker_uuid The UUID of the channel performing the park.
	 * \param app_data Data to pass to the Park application
	 *
	 * \note This must be called within the context of the \ref AstBridging Bridging API.
	 * External entities should not call this method directly, but should instead use
	 * the direct call parking method or the blind transfer method.
	 *
	 * \retval 0 on success
	 * \retval non-zero on error
	 */
	int (* parking_park_bridge_channel)(struct ast_bridge_channel *parkee, const char *parkee_uuid, const char *parker_uuid, const char *app_data);

	/*! \brief The module info for the module registering this parking provider */
	struct ast_module *module;
};

/*!
 * \brief Determine if the context/exten is a "parking" extension
 *
 * \retval 0 if the extension is not a parking extension
 * \retval 1 if the extension is a parking extension
 */
int ast_parking_is_exten_park(const char *context, const char *exten);

/*!
 * \brief Park the bridge and/or callers that this channel is in
 *
 * \param parker The bridge_channel parking the bridge
 * \param[out] exten Optional.  The parking exten to access the parking lot.
 * \param length Optional. If \c exten is specified, the size of the buffer.
 *
 * \note This is safe to be called outside of the \ref AstBridging Bridging API.
 *
 * \note The exten parameter was intended to return the extension the channel or
 * bridge was parked at if the call succeeds.  However, accessing that information
 * is very difficult to do with the new asynchronous design.  That information may
 * not be available anywhere by the time this function currently returns.
 *
 * Only, chan_skinny is known to call this function and use the exten parameter
 * for the phone display.
 *
 * \retval 0 on success
 * \retval non-zero on error
 */
int ast_parking_park_call(struct ast_bridge_channel *parker, char *exten, size_t length);

/*!
 * \brief Perform a blind transfer to a parking extension.
 *
 * \param parker The \ref bridge_channel object that is initiating the parking
 * \param context The context to blind transfer to
 * \param exten The extension to blind transfer to
 * \param exten The extension to blind transfer to
 * \param parked_channel_cb Execute the following function on the channel that gets parked
 * \param parked_channel_data Data for the parked_channel_cb
 *
 * \note If the bridge \ref parker is in has more than one other occupant, the entire
 * bridge will be parked using a Local channel
 *
 * \note This is safe to be called outside of the \ref AstBridging Bridging API.
 *
 * \retval 0 on success
 * \retval non-zero on error
 */
int ast_parking_blind_transfer_park(struct ast_bridge_channel *parker, const char *context,
	const char *exten, transfer_channel_cb parked_channel_cb, struct transfer_channel_data *parked_channel_data);

/*!
 * \brief Perform a direct park on a channel in a bridge.
 *
 * \param parkee The channel in the bridge to be parked.
 * \param parkee_uuid The UUID of the channel being packed.
 * \param parker_uuid The UUID of the channel performing the park.
 * \param app_data Data to pass to the Park application
 *
 * \note This must be called within the context of the \ref AstBridging Bridging API.
 * External entities should not call this method directly, but should instead use
 * the direct call parking method or the blind transfer method.
 *
 * \retval 0 on success
 * \retval non-zero on error
 */
int ast_parking_park_bridge_channel(struct ast_bridge_channel *parkee, const char *parkee_uuid, const char *parker_uuid, const char *app_data);

/*!
 * \brief Register a parking provider
 *
 * \param fn_table The \ref ast_parking_bridge_feature_fn_table to register
 *
 * \retval 0 on success
 * \retval -1 on error
 */
int ast_parking_register_bridge_features(struct ast_parking_bridge_feature_fn_table *fn_table);

/*!
 * \brief Unregister the current parking provider
 *
 * \param The module name of the provider to unregister
 *
 * \retval 0 if the parking provider \c module_name was unregsistered
 * \retval -1 on error
 */
int ast_parking_unregister_bridge_features(const char *module_name);

/*!
 * \brief Check whether a parking provider is registered
 *
 * \retval 0 if there is no parking provider regsistered
 * \retval 1 if there is a parking provider regsistered
 */
int ast_parking_provider_registered(void);
