#include <stdio.h>
#include <string.h>
#include "./include/q765_5e.h"

void apm_decode_action(ActionInd_struct *ptr, const u8 *flw_ptr, u8 length)
{
	ptr->pres = 1;
	ptr->comp_info = flw_ptr[0];
	ptr->val = flw_ptr[1];
}

u32 apm_encode_action(u8 *flw_ptr, const ActionInd_struct *ptr)
{
	flw_ptr[0] = ptr->comp_info;
	flw_ptr[1] = ptr->val;
	return 2;
}

void apm_decode_bncid(BncId_struct *ptr, const u8 *flw_ptr, u8 length)
{
	ptr->pres = 1;
	ptr->comp_info = flw_ptr[0];
	ptr->len = length - 1;
	memcpy(ptr->val, flw_ptr+1, ptr->len);
}

u32 apm_encode_bncid(u8 *flw_ptr, const BncId_struct *ptr)
{
	flw_ptr[0] = ptr->comp_info;
	memcpy(flw_ptr+1, ptr->val, ptr->len);
	return ptr->len + 1;
}

void apm_decode_bncchr(BncChr_struct *ptr, const u8 *flw_ptr, u8 length)
{
	ptr->pres = 1;
	ptr->comp_info = flw_ptr[0];
	ptr->val = flw_ptr[1];
}

u32 apm_encode_bncchr(u8 *flw_ptr, const BncChr_struct *ptr)
{
	flw_ptr[0] = ptr->comp_info;
	flw_ptr[1] = ptr->val;
	return 2;
}

void apm_decode_bcinfo(BcInfo_struct *ptr, const u8 *flw_ptr, u8 length)
{
	ptr->pres = 1;
	ptr->comp_info = flw_ptr[0];
	ptr->bctp.bvei = (flw_ptr[1] >> 6) & 0x01;
	ptr->bctp.btcp_version = flw_ptr[1] & 0x1f;
	ptr->bctp.tpei = (flw_ptr[2] >> 6) & 0x01;
	ptr->bctp.tunnel_protocol = flw_ptr[2] & 0x3f;
	ptr->bctp.ipbcp_len = length - 3;
	memcpy(ptr->bctp.ipbcp_content, flw_ptr+3, ptr->bctp.ipbcp_len);
}

u32 apm_encode_bcinfo(u8 *flw_ptr, const BcInfo_struct *ptr)
{
	flw_ptr[0] = ptr->comp_info;
	flw_ptr[1] = (ptr->bctp.bvei << 6) + (1 << 5) + ptr->bctp.btcp_version;
	flw_ptr[2] = (ptr->bctp.tpei << 6) + ptr->bctp.tunnel_protocol;
	memcpy(flw_ptr+3, ptr->bctp.ipbcp_content, ptr->bctp.ipbcp_len);
	return ptr->bctp.ipbcp_len + 3;
}

void apm_decode_bctunnel(BcTunnel_struct *ptr, const u8 *flw_ptr, u8 length)
{
	ptr->pres = 1;
	ptr->comp_info = flw_ptr[0];
	ptr->val = flw_ptr[1];
}

u32 apm_encode_bctunnel(u8 *flw_ptr, const BcTunnel_struct *ptr)
{
	flw_ptr[0] = ptr->comp_info;
	flw_ptr[1] = ptr->val;
	return 2;
}

void apm_decode_signaltype(SignalType_struct *ptr, const u8 *flw_ptr, u8 length)
{
	ptr->pres = 1;
	ptr->comp_info = flw_ptr[0];
	ptr->val = flw_ptr[1];
}

u32 apm_encode_signaltype(u8 *flw_ptr, const SignalType_struct *ptr)
{
	flw_ptr[0] = ptr->comp_info;
	flw_ptr[1] = ptr->val;
	return 2;
}

void apm_decode_duration(Duration_struct *ptr, const u8 *flw_ptr, u8 length)
{
	ptr->pres = 1;
	ptr->comp_info = flw_ptr[0];
	ptr->val = (flw_ptr[1] << 8) + flw_ptr[2];
}

u32 apm_encode_duration(u8 *flw_ptr, const Duration_struct *ptr)
{
	flw_ptr[0] = ptr->comp_info;
	flw_ptr[1] = ptr->val >> 8;
	flw_ptr[2] = ptr->val & 0xff;
	return 3;
}

void apm_decode(ApmUser_struct *ptr, const u8 *flw_ptr, u8 length)
{
	const u8 *old_ptr = flw_ptr;
	
	while(flw_ptr+flw_ptr[1]+2-old_ptr <= length)
	{
		if(*flw_ptr == 0)
			break;
		switch(*flw_ptr)
		{
			case AP_ACTION:
				apm_decode_action(&ptr->action, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case AP_BNCID:
				apm_decode_bncid(&ptr->bnc_id, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case AP_BNCCHR:
				apm_decode_bncchr(&ptr->bnc_chr, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case AP_BCINFO:
				apm_decode_bcinfo(&ptr->bc_info, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case AP_BCTUNNEL:
				apm_decode_bctunnel(&ptr->bc_tunnel, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case AP_SIGNALTYPE:
				apm_decode_signaltype(&ptr->signal_type, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case AP_DURATION:
				apm_decode_duration(&ptr->duration, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			default:
				flw_ptr += flw_ptr[1] + 2;
				break;
		}
	}
}

u32 apm_encode(u8 *flw_ptr, const ApmUser_struct *ptr)
{
	u8 *old_ptr = flw_ptr;
	
	if(ptr->action.pres == 1)
	{
		flw_ptr[0] = AP_ACTION;
		flw_ptr[1] = apm_encode_action(flw_ptr+2, &ptr->action);
		flw_ptr += flw_ptr[1] + 2;
	}
	if(ptr->bnc_id.pres == 1)
	{
		flw_ptr[0] = AP_BNCID;
		flw_ptr[1] = apm_encode_bncid(flw_ptr+2, &ptr->bnc_id);
		flw_ptr += flw_ptr[1] + 2;
	}
	if(ptr->bnc_chr.pres == 1)
	{
		flw_ptr[0] = AP_BNCCHR;
		flw_ptr[1] = apm_encode_bncchr(flw_ptr+2, &ptr->bnc_chr);
		flw_ptr += flw_ptr[1] + 2;
	}
	if(ptr->bc_info.pres == 1)
	{
		flw_ptr[0] = AP_BCINFO;
		flw_ptr[1] = apm_encode_bcinfo(flw_ptr+2, &ptr->bc_info);
		flw_ptr += flw_ptr[1] + 2;
	}
	if(ptr->bc_tunnel.pres == 1)
	{
		flw_ptr[0] = AP_BCTUNNEL;
		flw_ptr[1] = apm_encode_bctunnel(flw_ptr+2, &ptr->bc_tunnel);
		flw_ptr += flw_ptr[1] + 2;
	}
	if(ptr->signal_type.pres == 1)
	{
		flw_ptr[0] = AP_SIGNALTYPE;
		flw_ptr[1] = apm_encode_signaltype(flw_ptr+2, &ptr->signal_type);
		flw_ptr += flw_ptr[1] + 2;
	}
	if(ptr->duration.pres == 1)
	{
		flw_ptr[0] = AP_DURATION;
		flw_ptr[1] = apm_encode_duration(flw_ptr+2, &ptr->duration);
		flw_ptr += flw_ptr[1] + 2;
	}
	return flw_ptr - old_ptr;
}


