/**
 * @file bfcp/reply.c BFCP Reply
 *
 * Copyright (C) 2010 Creytiv.com
 */
#include <re_types.h>
#include <string.h>
#include <re_fmt.h>
#include <re_mem.h>
#include <re_mbuf.h>
#include <re_list.h>
#include <re_sa.h>
#include <re_tmr.h>
#include <re_bfcp.h>
#include "bfcp.h"


enum {
	BFCP_T2  = 10000,
};


static void tmr_handler(void *arg)
{
	struct bfcp_conn *bc = arg;

	bc->mb = mem_deref(bc->mb);
}


/**
 * Send a BFCP response
 *
 * @param bc      BFCP connection
 * @param req     BFCP request message
 * @param prim    BFCP Primitive
 * @param attrc   Number of attributes
 *
 * @return 0 if success, otherwise errorcode
 */
int bfcp_reply(struct bfcp_conn *bc, const struct bfcp_msg *req,
	       enum bfcp_prim prim, unsigned attrc, ...)
{
	va_list ap;
	int err;

	if (!bc || !req)
		return EINVAL;

	bc->mb = mem_deref(bc->mb);
	tmr_cancel(&bc->tmr2);

	bc->mb = mbuf_alloc(64);
	if (!bc->mb)
		return ENOMEM;

	va_start(ap, attrc);
	err = bfcp_msg_vencode(bc->mb, req->ver, true, prim, req->confid,
			       req->tid, req->userid, attrc, &ap);
	va_end(ap);

	if (err)
		goto out;

	bc->mb->pos = 0;

	err = bfcp_send(bc, &req->src, bc->mb);
	if (err)
		goto out;

	bc->st.prim   = req->prim;
	bc->st.confid = req->confid;
	bc->st.tid    = req->tid;
	bc->st.userid = req->userid;

	tmr_start(&bc->tmr2, BFCP_T2, tmr_handler, bc);

 out:
	if (err)
		bc->mb = mem_deref(bc->mb);

	return err;
}


/**
 * Send a BFCP error response with details
 *
 * @param bc      BFCP connection
 * @param req     BFCP request message
 * @param code    Error code
 * @param details Error details
 * @param len     Details length
 *
 * @return 0 if success, otherwise errorcode
 */
int bfcp_edreply(struct bfcp_conn *bc, const struct bfcp_msg *req,
		 enum bfcp_err code, const uint8_t *details, size_t len)
{
	struct bfcp_errcode errcode;

	errcode.code    = code;
	errcode.details = (uint8_t *)details;
	errcode.len     = len;

	return bfcp_reply(bc, req, BFCP_ERROR, 1,
			  BFCP_ERROR_CODE, 0, &errcode);
}


/**
 * Send a BFCP error response
 *
 * @param bc      BFCP connection
 * @param req     BFCP request message
 * @param code    Error code
 *
 * @return 0 if success, otherwise errorcode
 */
int bfcp_ereply(struct bfcp_conn *bc, const struct bfcp_msg *req,
		enum bfcp_err code)
{
	return bfcp_edreply(bc, req, code, NULL, 0);
}
