#include "sh_conf.h"

Ro_LinkSet rolkset={0,0};

int GetRoDiamIdPeer(DiamId_t **realm, DiamId_t **host, int bSms)
{
    struct peer_hdr*peer = NULL;
    SH_CONF_S *pcfg = NULL;
    int i;
    int ret = -1;
    int peer_state = -1;
    if (bSms)
    {
        int curlk = rolkset.cursmslk;
        for (i=0; i<rolkset.smslknum; i++)
        {
            curlk = (curlk + i +1) % rolkset.smslknum;
            pcfg = &rolkset.smslk[curlk].cfg;
            if (pcfg->pi_diamid_peer != NULL)
            {
                ret = fd_peer_getbyid(pcfg->pi_diamid_peer, strlen(pcfg->pi_diamid_peer), 0, &peer);
                if( !ret && peer )
                {
                  peer_state = fd_peer_get_state(peer);
                  if( STATE_OPEN == peer_state ) 
                  {
                    if (rolkset.smslk[curlk].bconn == 0)
                    {
                      printf("diam peer disconn to conn, host[%s]\r\n", pcfg->pi_diamid_peer);
                      rolkset.smslk[curlk].bconn = 1;
                    }
                    *realm = pcfg->pi_diamid_realm_peer;
                    *host = pcfg->pi_diamid_peer;
                    return 1;
                  } 
                  else 
                  {
                    if (rolkset.smslk[curlk].bconn == 1)
                    {
                      printf("diam peer conn to discon, host[%s]\r\n", pcfg->pi_diamid_peer);
                      rolkset.smslk[curlk].bconn = 0;
                    }
                  }    
                } 
                else 
                {
                  printf("diam peer NA, host[%s], ret[%d], peer[%p]\r\n", pcfg->pi_diamid_peer, ret, peer);
                  rolkset.smslk[curlk].bconn = 0;
                }
            }
        }
    }
    else
    {
        int curlk = rolkset.curvoicelk;
        for (i=0; i<rolkset.voicelknum; i++)
        {
            curlk = (curlk + i +1) % rolkset.voicelknum;
            pcfg = &rolkset.voicelk[curlk].cfg;
            if (pcfg->pi_diamid_peer != NULL)
            {
                ret = fd_peer_getbyid(pcfg->pi_diamid_peer, strlen(pcfg->pi_diamid_peer), 0, &peer);
                if( !ret && peer )
                {
                  peer_state = fd_peer_get_state(peer);
                  if( STATE_OPEN == peer_state ) 
                  {
                    if (rolkset.voicelk[curlk].bconn == 0)
                    {
                      printf("diam peer disconn to conn, host[%s]\r\n", pcfg->pi_diamid_peer);
                      rolkset.voicelk[curlk].bconn = 1;
                    }
                    *realm = pcfg->pi_diamid_realm_peer;
                    *host = pcfg->pi_diamid_peer;
                    return 1;
                  } 
                  else 
                  {
                    if (rolkset.voicelk[curlk].bconn == 1)
                    {
                      printf("diam peer conn to discon, host[%s]\r\n", pcfg->pi_diamid_peer);
                      rolkset.voicelk[curlk].bconn = 0;
                    }
                  }    
                } 
                else 
                {
                  printf("diam peer NA, host[%s], ret[%d], peer[%p]\r\n", pcfg->pi_diamid_peer, ret, peer);
                  rolkset.voicelk[curlk].bconn = 0;
                }
            }
        }
    }
    return 0;
}

int AddRoLink(SH_CONF_S *cfg, uint16_t port, int bSms)
{
    if (bSms)
    {
        if(rolkset.smslknum >= MaxRoLinkNum)
        {
            return 0;
        }
        
        rolkset.smslk[rolkset.smslknum].cfg.pi_diamid_peer = strdup(cfg->pi_diamid_peer);
        rolkset.smslk[rolkset.smslknum].cfg.pi_diamid_realm_peer = strdup(cfg->pi_diamid_realm_peer);
        rolkset.smslk[rolkset.smslknum].cfg.peer_port = port;
        rolkset.smslknum++;
    }
    else
    {
        if(rolkset.voicelknum >= MaxRoLinkNum)
        {
            return 0;
        }
        
        rolkset.voicelk[rolkset.voicelknum].cfg.pi_diamid_peer = strdup(cfg->pi_diamid_peer);
        rolkset.voicelk[rolkset.voicelknum].cfg.pi_diamid_realm_peer = strdup(cfg->pi_diamid_realm_peer);
        rolkset.voicelk[rolkset.voicelknum].cfg.peer_port = port;
        rolkset.voicelknum++;
    }
    return 1;
}

SH_CONF_S				g_sh_conf_ext;
//SH_CONF_S				g_rovoice_conf_ext;
//SH_CONF_S				g_rosms_conf_ext;

#define SH_PARSE_BUFFER_LEN 1024

static char* shParseStr_(char* buffer, char* _key, char *ret_str, int flag_from_begin)
{
	char *pos = strstr(buffer, _key);
	char *pos_1 = NULL;
	char *pos_2 = NULL;
	if(NULL != pos && (flag_from_begin ? (buffer == pos) : 1) )
	{
		pos_1 = strstr(pos, "\"");
		if(NULL != pos_1)
		{
			pos_2 = strstr(pos_1 + 1, "\"");
			if(NULL != pos_2)
			{
				memcpy(ret_str, pos_1 + 1, pos_2 - pos_1 - 1);
				ret_str[pos_2 - pos_1] = '\0';
				// fprintf(stderr, "%s=%s\n", _key, ret_str);
				return ret_str;
			}
		}
	}
	return NULL;
}

static char* shParseStr(char* buffer, char* _key, char *ret_str)
{
	return shParseStr_(buffer, _key, ret_str, 1);
}
static char* shParseStrSub(char* buffer, char* _key, char *ret_str)
{
	return shParseStr_(buffer, _key, ret_str, 0);
}

uint16_t shParseInt(char* buffer, char* _key, uint16_t* ret_int)
{
	char buff_num[16] = {0};

	char *pos = strstr(buffer, _key);
	char *pos_1 = NULL;
	char *pos_2 = NULL;
	/* first address is start of the line */
	if(NULL != pos && buffer == pos)
	{
		pos_1 = strstr(pos, "=");
		if(NULL != pos_1)
		{
			pos_2 = strstr(pos_1 + 1, ";");
			if(NULL != pos_2)
			{
				memcpy(buff_num, pos_1 + 1, pos_2 - pos_1 - 1);
				*ret_int = atol( buff_num );
				// fprintf(stderr, "%s=%d\n", _key, *ret_int);
				return *ret_int;
			}
		}
	}
	return 0;
}

int shParseFlags(char* buffer, char* _key, char* no_flag_key)
{
	char *pos = strstr(buffer, _key);
	char *pos_1 = NULL;
	char *pos_2 = NULL;
	/* first address is start of the line */
	if(NULL != pos && buffer == pos)
	{
		pos_1 = strstr(pos, "{");
		if(NULL != pos_1)
		{
			pos_2 = strstr(pos_1 + 1, "}");
			if(NULL != pos_2)
			{
				if(strstr( pos_1 + 1, no_flag_key) )
				{
					// fprintf(stderr, "%s\n", no_flag_key);
					return 1;
				}
			}
		}
	}
	return 0;
}

int shParse_(struct fd_config * conf)
{
	FILE*  fd;
	char buffer[SH_PARSE_BUFFER_LEN] = {0};
	char ret_str[512] = {0};

	/* Create input file descriptor */
	fd = fopen (conf->cnf_file, "r");
	if (fd == NULL)
	{
		perror ("open");
		return 2;
	}

    conf->ro_voiceport = 29100;
    conf->ro_smsport = 19500;
    strcpy(conf->service_context_voice, "agrandtech_ro@3gpp.org");
    strcpy(conf->service_context_sms, "agrandtech_sms@3gpp.org");
	/* Copy process */
	while((fgets(buffer, SH_PARSE_BUFFER_LEN, fd)) != NULL)
	{	
		if( shParseStr(buffer, "Identity", ret_str) )
		{
			conf->cnf_diamid		= strdup(ret_str);
			conf->cnf_diamid_len 	= strlen(ret_str);

			memset( ret_str, 0, strlen(ret_str) );
		}
		if( shParseStr(buffer, "Realm",	ret_str) )
		{
			conf->cnf_diamrlm		= strdup(ret_str);
			conf->cnf_diamrlm_len 	= strlen(ret_str);

			memset( ret_str, 0, strlen(ret_str) );
		}
		if( shParseStr(buffer, "ServiceCxtRoVoice", ret_str) )
		{
            strcpy(conf->service_context_voice, ret_str);
			memset( ret_str, 0, strlen(ret_str) );
		}
		if( shParseStr(buffer, "ServiceCxtRoSms", ret_str) )
		{
            strcpy(conf->service_context_sms, ret_str);
			memset( ret_str, 0, strlen(ret_str) );
		}
		shParseInt(buffer, "RoVoicePort", &conf->ro_voiceport);
		shParseInt(buffer, "RoSmsPort", &conf->ro_smsport);
		shParseInt(buffer, "Port",	&conf->cnf_port);
		shParseInt(buffer, "SecPort",	&conf->cnf_port_tls);
		shParseInt(buffer, "SCTPStr",	&conf->cnf_sctp_str);

		if( shParseFlags(buffer, "ConnectPeer", "No_TLS") )
		{
			conf->cnf_sec_data.tls_disabled = 1;
		}
		if( shParseFlags(buffer, "ConnectPeer", "No_FWD") )
		{
			conf->cnf_flags.no_fwd = 1;
		}
		if( shParseFlags(buffer, "ConnectPeer", "No_IP4") )
		{
			conf->cnf_flags.no_ip4 = 1;
		}
		if( shParseFlags(buffer, "ConnectPeer", "No_IP6") )
		{
			conf->cnf_flags.no_ip6 = 1;
		}
		if( shParseFlags(buffer, "ConnectPeer", "No_TCP") )
		{
			conf->cnf_flags.no_tcp = 1;
		}
		if( shParseFlags(buffer, "ConnectPeer", "No_SCTP") )
		{
			conf->cnf_flags.no_sctp = 1;
		}
		if( shParseFlags(buffer, "ConnectPeer", "Prefer_TCP") )
		{
			conf->cnf_flags.pr_tcp = 1;
		}

		memset(buffer, 0, SH_PARSE_BUFFER_LEN);
	}
	
	fclose (fd);

	conf->cnf_flags.tls_alg = 0;

	return 0;
}

int shParseExt(struct fd_config * conf)
{
	FILE*  fd;
	char buffer[SH_PARSE_BUFFER_LEN] = {0};
	char ret_str[512] = {0};
	
	fd = fopen (conf->cnf_file, "r");
	if(NULL == fd)
	{
		perror ("open");
		return 2;
	}

	while((fgets(buffer, SH_PARSE_BUFFER_LEN, fd)) != NULL)
	{	
		shParseInt( buffer, "ServiceMod",	(uint16_t*)(&g_sh_conf_ext.mode) );
		
		if( shParseStr(buffer, "ConnectPeer", ret_str) )
		{
			g_sh_conf_ext.pi_diamid_peer		= strdup(ret_str);
			memset( ret_str, 0, strlen(ret_str) );

			if( shParseStrSub(buffer, "Realm", ret_str) )
			{
				g_sh_conf_ext.pi_diamid_realm_peer		= strdup(ret_str);
				memset( ret_str, 0, strlen(ret_str) );
			}
            g_sh_conf_ext.peer_port = fd_g_config->cnf_port;
            if( shParseFlags(buffer, "ConnectPeer", "Ro_SMS") )
            {
                //g_rosms_conf_ext.pi_diamid_peer = strdup(g_sh_conf_ext.pi_diamid_peer);
                //g_rosms_conf_ext.pi_diamid_realm_peer = strdup(g_sh_conf_ext.pi_diamid_realm_peer);
                //g_rosms_conf_ext.peer_port = fd_g_config->ro_smsport;
                AddRoLink(&g_sh_conf_ext, fd_g_config->ro_smsport, 1);
                free(g_sh_conf_ext.pi_diamid_peer);
                g_sh_conf_ext.pi_diamid_peer = NULL;
                free(g_sh_conf_ext.pi_diamid_realm_peer);
                g_sh_conf_ext.pi_diamid_realm_peer = NULL;
            }
            if( shParseFlags(buffer, "ConnectPeer", "Ro_VOICE") )
            {
                //g_rovoice_conf_ext.pi_diamid_peer = strdup(g_sh_conf_ext.pi_diamid_peer);
                //g_rovoice_conf_ext.pi_diamid_realm_peer = strdup(g_sh_conf_ext.pi_diamid_realm_peer);
                //g_rovoice_conf_ext.peer_port = fd_g_config->ro_voiceport;
                AddRoLink(&g_sh_conf_ext, fd_g_config->ro_voiceport, 0);
                free(g_sh_conf_ext.pi_diamid_peer);
                g_sh_conf_ext.pi_diamid_peer = NULL;
                free(g_sh_conf_ext.pi_diamid_realm_peer);
                g_sh_conf_ext.pi_diamid_realm_peer = NULL;
            }
		}


		shParseInt( buffer, "LogLevel",	(uint16_t*)(&fd_g_debug_lvl) );

		memset(buffer, 0, SH_PARSE_BUFFER_LEN);
	}
	
	fclose (fd);
	
	return 0;
}

int shParse(struct fd_config * conf)
{
	return shParse_(conf) || shParseExt(conf);
}
