/**************************************************************
 * file: adslUtils.c
 *
 * This file contains functions to add user cmv into cmvs.txt.
 **************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include "../../linux/drivers/net/inc/sysconf.h"
#include "../inc/appdefines.h"
#include "../inc/apptypes.h"
#include "../../linux/net/adi/inc/stackios.h"
#include "../../linux/drivers/net/fusiv_toolkit/ap_code/inc/adsl/adsllib.h"
#include"../../linux/drivers/net/fusiv_misc/snmp/adslmode.h"

#define		CR		'\r'
#define		LF		'\n'

#define CMV_FILE	"/bin/cmvs.txt"
#define	MATCH_CMV	0
#define	MATCH_GROUP	1

typedef struct 
{
	unsigned char cmv[8];
	unsigned short group;
	
} STRATIPHY_CMV_LOOKUP_TABLE;

STRATIPHY_CMV_LOOKUP_TABLE CMVLookupTable [] = 
{ 
	{"CNTL",1},
	{"STAT",2},
	{"INFO",3},
	{"TEST",4},
	{"OPTN",5},
	{"RATE",6},
	{"PLAM",7},
	{"CNFG",8},
	{"", 0}
};


/*********************************************************/
/* function: readLine()                                  */
/* the function is to read one line (up to line feed)    */
/* from the file.                                        */
/*********************************************************/
int readLine(int fd, char *buffer)
{
	int byte, i = 0;
    char b[4];

//printf("readLine\n");
	memset(buffer, 0, 255);
//printf("memset\n");
	/* skip all CR and LF at the current line */
	while((byte = read(fd, b, 1)) == 1)
	{
//printf("%c", b[0]);
		if(b[0] != EOF)
		{
			buffer[i] = b[0];
			i++;
			if(b[0] == LF)
				break;
		}
		else // reach the end of line
		{
			if(i > 0)
			{ //the line is not end with CR/LF - add CR/LF
				buffer[i] = LF;
				write(fd, &buffer[i], 1);
				i++;
			}
		}
	}     
	buffer[i] = '\0';
	return (i);
}

void skipFront(char ** pLine)
{
	while(**pLine == ' ' || **pLine == '/' || **pLine == '\t' || **pLine == '#' || **pLine == CR || **pLine == LF)
	{
		(*pLine)++;
	}
}

/*********************************************************
 * function: getToken()
 *
 ********************************************************/
int getToken(char *token, char **pLine)
{
	int		i = 0;
	while((**pLine != ' ')&&(**pLine != '\t')&&(**pLine != '/')&&(**pLine != '\r')&&(**pLine != '\n')&&(**pLine != '\0'))
	{
		token[i++] = toupper(**pLine);
		(*pLine)++;
	}
	token[i] = '\0';
	return i;
}
/*************************************
 * this function is to search CMVLookupTable to match
 * the cmv for group number
 *************************************
 */
int	matchCMV(char *cmv, UINT16 *group, int direction)
{
   int		i = 0;
	while(CMVLookupTable[i].group)
	{
		if(direction == MATCH_CMV)
		{
			if(strcmp(cmv, CMVLookupTable[i].cmv) == 0) //match
			{
				*group = CMVLookupTable[i].group;
				return 1;
			}
		}
		else //match group
		{
			if(*group == CMVLookupTable[i].group)
			{
				strcpy(cmv, CMVLookupTable[i].cmv);
				return 1;
			}
		}
		i++;
	}
	return 0;
}

void htoas(char *s, UINT32 len)
{
	int i;
	int x;

	for(i=0; i<8; i++)
	{
		x = (len >> (7-i)*4) & 0x0f;
		if((x>=0) && (x<=9))
			s[i] = x+'0';
		else
			s[i] = (x-10) + 'a';
	}
	s[i] = '.';
	s[i+1] = '\0';
}
		
int	parseCMV(char **pLine, UINT16 *group, UINT16 *pAddr, UINT16 *pIndex, UINT32 *pValue)
{
	char 	*pTemp;
	char	token[8];
	int 	i, n;

	skipFront(pLine);
	getToken(token, pLine);
	if(matchCMV(token, group, MATCH_CMV) == 0)
		return 0;

	skipFront(pLine);
	getToken(token, pLine);	//address
	*pAddr = atoi(token);
	skipFront(pLine);
	getToken(token, pLine);	//index
	*pIndex = atoi(token);
	skipFront(pLine);
	pTemp = *pLine;
	getToken(token, pLine);
	*pValue = 0;
	for(i = 0; i < 8; i++)
	{
		if((token[i] >= '0')&&(token[i] <= '9'))
		{
			n = token[i] - '0';
		}
		else
			if((token[i] >= 'A')&&(token[i] <= 'F'))
				n = token[i] - 'A' + 0x0a;
			else
				if((token[i] >= 'a')&&(token[i] <= 'f'))
					n = token[i] - 'a' + 0x0a;

		*pValue = (*pValue << 4) + n;
	}
	*pLine = pTemp;				//put the pLine to pointing to value in the buffer
	return 1;
}

int convertCMV(char *lineBuff, UserCmv_t *userCMV)
{
	char	asc2[8], asc3[12];
	int		len = 5;
	memset(lineBuff, 0, 255);
	matchCMV(asc2, &userCMV->group, MATCH_GROUP);
	htoas(asc3, userCMV->value);
	sprintf(lineBuff, "%s %d %d %s\n", asc2, userCMV->address, userCMV->index, asc3);
	return strlen(lineBuff);
}	

/**********************************************************
 * adslUserCMVAdd()
  * userCMV - contains new CMV 
  * function searches cmvs.txt to match user added new cmv.
  * if the cmv type is already existed in cmvs.txt, it just update
  * the cmv value. if not exist, add the new one into cmvs.txt
  * at the end of file.
************************************************************/
int adslUserCMVAdd(UserCmv_t *userCMV)
{
	int	fd = 0;
	UINT16	group;
    UINT16 	address;
    UINT16 	index;
	UINT32	value;
	char  	lineBuf[256], *pLine, asc2[16];
	int		len;
	UINT16	userGroup, userAddr, userIndex;
	UINT32	userValue;
	UserCmv_t localCMV;

	localCMV.group = userCMV->group;
	localCMV.address = userCMV->address;
	localCMV.index = userCMV->index;
	localCMV.value = userCMV->value;

	if((fd = open(CMV_FILE, O_RDWR)) < 0)
	{
		printf("Failed to open %s\n", CMV_FILE);
		return FAILURE;
	}
	while((len = readLine(fd, lineBuf)) > 0)
	{
		pLine = lineBuf;
		if(parseCMV(&pLine, &group, &address, &index, &value))
		{
			if((group == localCMV.group)&&(address == localCMV.address)&&(index == localCMV.index))
			{
#if IS_ADSL_BONDING
				if((value & 0xffff0000) == (localCMV.value & 0xffff0000))
				{
					value = localCMV.value;
					break;
				}

#else
				value = localCMV.value;
				break;
#endif
			}
		}
	}
	if(len == 0) //reach end of file
	{
		//just add the line
		len = convertCMV(lineBuf, &localCMV);
	}
	else //replace the value and write back the line
	{		
		htoas(asc2, value);				
		memcpy(pLine, asc2, 8);
		lseek(fd, 0-len, SEEK_CUR);					//move back the file point to the beginning of the current line
	}
	write(fd, lineBuf, len);
	close(fd);

	return SUCCESS;
}

