/*
 * rpc.c
 *
 *  Created on: 27 May 2014
 *      Author: jaybeepee
 */
#include "cdp_rpc.h"
#include "peermanager.h"
#include "peerstatemachine.h"
#include "receiver.h"
#include "../../core/str.h"
#include "../../core/dprint.h"

extern dp_config *config;
extern peer_list_t *peer_list;
extern gen_lock_t *peer_list_lock;
extern char *dp_states[];

static const char *cdp_rpc_disable_peer_doc[2] = {"disable diameter peer", 0};
static const char *cdp_rpc_enable_peer_doc[2] = {"enable diameter peer", 0};
static const char *cdp_rpc_list_peers_doc[2] = {
		"list diameter peers and their state", 0};

static void cdp_rpc_enable_peer(rpc_t *rpc, void *ctx)
{
	peer *cdp_peer;
	str peer_fqdn;

	if(rpc->scan(ctx, "S", &peer_fqdn) < 1) {
		rpc->fault(ctx, 400, "required peer fqdn argument");
		return;
	}

	cdp_peer = get_peer_by_fqdn(&peer_fqdn);
	if(cdp_peer != NULL) {
		LM_DBG("Enabling CDP Peer: [%.*s]\n", peer_fqdn.len, peer_fqdn.s);
		cdp_peer->disabled = 0;
		return;
	}
	rpc->fault(ctx, 400, "peer not found");
	return;
}

static void cdp_rpc_disable_peer(rpc_t *rpc, void *ctx)
{
	peer *cdp_peer;
	str peer_fqdn;

	if(rpc->scan(ctx, "S", &peer_fqdn) < 1) {
		rpc->fault(ctx, 400, "required peer fqdn argument");
		return;
	}
	cdp_peer = get_peer_by_fqdn(&peer_fqdn);
	if(cdp_peer != NULL) {
		LM_DBG("Disabling CDP peer: [%.*s]\n", peer_fqdn.len, peer_fqdn.s);
		cdp_peer->disabled = 1;
		return;
	}

	rpc->fault(ctx, 400, "peer not found");
	return;
}

static void cdp_rpc_list_peers(rpc_t *rpc, void *ctx)
{
	void *peers_header;
	void *peers_container;
	void *peerdetail_container;
	void *peerapplication_container;
	peer *i, *j;
	int c;
	char buf[100];

	if(rpc->add(ctx, "{", &peers_header) < 0) {
		rpc->fault(ctx, 500, "Internal error creating top rpc");
		return;
	}

	if(rpc->struct_add(peers_header, "SSddddddd{", "Realm", &config->realm,
			   "Identity", &config->identity, "Accept unknown peers",
			   config->accept_unknown_peers, "Connect timeout",
			   config->connect_timeout, "Transaction timeout",
			   config->transaction_timeout, "Default auth session timeout",
			   config->default_auth_session_timeout, "Queue length",
			   config->queue_length, "Workers", config->workers, "Peer count",
			   config->peers_cnt, "Peers", &peers_container)
			< 0) {
		rpc->fault(ctx, 500, "Internal error creating peers header struct");
		return;
	}

	lock_get(peer_list_lock);
	i = peer_list->head;
	while(i) {
		lock_get(i->lock);
		if(rpc->struct_add(peers_container, "S{", "FQDN", &i->fqdn, "Details",
				   &peerdetail_container)
				< 0) {
			rpc->fault(
					ctx, 500, "Internal error creating peers container struct");
			lock_release(i->lock);
			return;
		}
		if(rpc->struct_add(peerdetail_container, "ssd", "State",
				   dp_states[(int)i->state], "Disabled",
				   i->disabled ? "True" : "False", "Last used",
				   i->last_selected)
				< 0) {
			rpc->fault(ctx, 500,
					"Internal error creating peer detail container struct");
			lock_release(i->lock);
			return;
		}
		if(rpc->struct_add(peerdetail_container, "{", "Applications",
				   &peerapplication_container)
				< 0) {
			rpc->fault(ctx, 500,
					"Internal error creating peer application container "
					"struct");
			lock_release(i->lock);
			return;
		}

		for(c = 0; c < i->applications_cnt; c++) {
			snprintf(buf, 100, "%d:%d", i->applications[c].id,
					i->applications[c].vendor);
			if(rpc->struct_add(
					   peerapplication_container, "s", "appid:vendorid", buf)
					< 0) {
				rpc->fault(ctx, 500,
						"Internal error creating appid/vendorid information");
				lock_release(i->lock);
				return;
			}
		}
		j = i;
		i = i->next;
		lock_release(j->lock);
	}
	lock_release(peer_list_lock);
}

rpc_export_t cdp_rpc[] = {
		{"cdp.disable_peer", cdp_rpc_disable_peer, cdp_rpc_disable_peer_doc, 0},
		{"cdp.enable_peer", cdp_rpc_enable_peer, cdp_rpc_enable_peer_doc, 0},
		{"cdp.list_peers", cdp_rpc_list_peers, cdp_rpc_list_peers_doc, 0},
		{0, 0, 0, 0}};
