
#include <stdlib.h>
#include <string.h>
#include "parseCsv.h"
parseFunc   parseFuncTbl[5] = {
	NULL,
	parseFixedTbl,
	parseLoopTbl,
	NULL,
	NULL
};

#define   FIELD_LEN	512

int	parseMsg(parseList *list, char *data, int size)
{
	
	int	ret, errcode;
	int	i;
	int	pos=0;
	parseFunc pFunc;
	if (size==-1){
		size=strlen(data);
	}
	
	errcode = _PARSECSV_EROR_OK;
	ret=_PARSECSV_EROR_MOREDATA;
	for (i = 0; list[i].type!= PARSE_TBL_END; i++)
	{
		if ( ret != _PARSECSV_EROR_MOREDATA){
			if ( ret==_PARSECSV_EROR_OK || ret==_PARSECSV_EROR_NODATA ){
				errcode=_PARSECSV_EROR_NODATA;
			}else{
				errcode=ret;
			}
			break;
		}
		pFunc = parseFuncTbl[list[i].type];
		if (pFunc)
			ret = pFunc(&list[i], data, &pos, size);
	}

	if ( errcode == _PARSECSV_EROR_OK )
	{
		errcode = ret;
	}
	return errcode;
}
/*
ret:
_PARSECSV_EROR_OK
_PARSECSV_EROR_NODATA
_PARSECSV_EROR_MOREDATA
_PARSECSV_EROR_CHEKLENGTH

_PARSECSV_EROR_TOOLONG
*/
int parseCommonTbl(void *addrStruc, parseData* tbl, char *data, int* startPos, int size)
{
	int			ret, errcode;
	int			i, len;
	char		buf[FIELD_LEN];
	
	errcode = _PARSECSV_EROR_OK;
	ret = _PARSECSV_EROR_MOREDATA;
	for (i = 0; tbl->type!= PARSE_TYPE_END; i++)
	{
		if (ret != _PARSECSV_EROR_MOREDATA){
			errcode = ret;
			break;
		}
		
		ret = parseCsvData(data, startPos, size, buf, &len);
		if ( ret <_PARSECSV_EROR_OK){
			errcode = ret;
			break;
		}
		if (tbl->size > 0 && len>tbl->size){
			errcode = _PARSECSV_EROR_CHEKLENGTH;
			break;
		}
		switch(tbl->type)
		{
			case PARSE_TYPE_INT:
				*(int *)(addrStruc + tbl->offset) = atoi(buf);
				break;
			case PARSE_TYPE_SHORT:
				*(short *)(addrStruc + tbl->offset) = (short)atoi(buf);
				break;
			case PARSE_TYPE_CHAR:
				strncpy(reinterpret_cast<char *>(addrStruc) + tbl->offset, buf, tbl->size);
				break;
			default:
				break;
		}
		tbl++;
	}
	if ( errcode == _PARSECSV_EROR_OK && ret == _PARSECSV_EROR_MOREDATA)
	{
		errcode = ret;
	}

	return errcode;
}



int parseFixedTbl(void *list, char *data, int* startPos, int size)
{
	char		buf[FIELD_LEN];
	int			errcode;
	parseList *	pList = (parseList *)list;
	
	errcode = parseCommonTbl(pList->addrHead, pList->tbl, data, startPos, size);
	
	return errcode;
}
/*
ret:
_PARSECSV_EROR_NODATA
_PARSECSV_EROR_MOREDATA
_PARSECSV_EROR_CHEKLENGTH

_PARSECSV_EROR_TOOLONG
*/
int parseLoopTbl(void *list, char *data, int* startPos, int size)
{
	int			ret, errcode;
	int			i, len;
	int			count;
	parseData*	tbl;
	char		buf[FIELD_LEN];
	int			pos;
	parseList *	pList = (parseList *)list;
	parseData*	TblHead = pList->tbl;
	void*		addrStruc = (void*)pList->addrHead;
	
	ret = parseCsvData(data, startPos, size, buf, &len);
	if ( ret <_PARSECSV_EROR_OK){
		errcode = ret;
		return errcode;
	}
	count = atoi(buf);
	switch(pList->countType)
	{
		case PARSE_TYPE_INT:
			*(int *)(pList->count) = count;
			break;
		case PARSE_TYPE_SHORT:
			*(short *)(pList->count) = (short)count;
			break;
		default:
			break;
	}
	if (ret==_PARSECSV_EROR_NODATA){
		ret = _PARSECSV_EROR_OK;
	}
	errcode = _PARSECSV_EROR_OK;
	for (i = 0; i<count; i++)
	{	
		if ( ret != _PARSECSV_EROR_MOREDATA){
			if ( ret==_PARSECSV_EROR_OK || ret==_PARSECSV_EROR_NODATA ){
				errcode=_PARSECSV_EROR_NODATA;
			}else{
				errcode=ret;
			}
			break;
		}
		ret = parseCommonTbl(addrStruc, pList->tbl, data, startPos, size);
		addrStruc+= pList->stSize;
	}
	if (errcode == _PARSECSV_EROR_OK)
	{
		errcode = ret;
	}

	return errcode;
	
}
/*
#define     TO_COPY(TO,POS)         \
if (to){\
*TO++= data[POS];\
}else{ \
TO++;\
}
*/
#define     TO_COPY(TO,POS)         \
if((TO-to+1)>FIELD_LEN){\
ret=_PARSECSV_EROR_TOOLONG;\
break;\
}\
*TO++= data[POS]\
/*
ret:
_PARSECSV_EROR_NODATA
_PARSECSV_EROR_MOREDATA
_PARSECSV_EROR_TOOLONG
*/
int parseCsvData(char* data, int* startPos, int size, char* to, int* len)
{
	int pos, _len;
	int ret = _PARSECSV_EROR_NODATA;
	char *_to = to;
	char ch = '\0';
	for (pos = *startPos; pos<size; pos++)
	{
		if (data[pos] == '\'' || data[pos] == '"')
		{
			if (ch == '\0'){
				ch = data[pos];
			}else if (ch == data[pos]){
				ch = '\0';
			}
			TO_COPY(_to, pos);
		}else if (data[pos] == ','){
			if (ch == '\0'){
				ret = _PARSECSV_EROR_MOREDATA;
				*startPos = pos+1;
				break;
			}else {
				TO_COPY(_to, pos);
			}
		}else{
			TO_COPY(_to, pos);
		}
	}
	_len = _to-to;
	if (ret <_PARSECSV_EROR_OK)
	{
		*len = _len;
		return ret;
	}else if (ret == _PARSECSV_EROR_NODATA){
		*startPos = -1;
	}
	
	*_to = '\0';
	if ((*to == '\'' || *to == '"')&& (_to-1!= to)&& *to == *(_to-1))
	{
		*(_to-1) = '\0';
		memmove(to, to+1, _to-to-1);
		_len-= 2;
	}
	*len = _len;
	return ret;
}


