/************************************************************************
 * AUTHOR: NiuJiuRu
 * FILENAME: swfile.c
 * CONTENT: 常用的文件操作接口函数
 * NOTE:
 * HISTORY:
 * 1, [2010-08-19] created by NiuJiuRu
 * 2, [2014-01-10] 整体优化修改
 * 3, [2014-01-22] 整体优化修改
 * 4, [2014-06-24] a) 修正"sw_file_setCfgString()"函数设置已存在的节时, 无
 *                    法设置成功的问题
 *                 b) 修正"sw_file_setCfgString()"函数自动新增的节前没有回
 *                    车换行的问题
 *                 c) 加强"sw_file_setCfgString()"函数的缓存溢出判断
 ************************************************************************/
#include "swapi.h"
#include "swstring.h"
#include "swfile.h"

/* 装载文件 */
int sw_file_load(const char *filename, const char *mode, char *buf, int bufSize)
{
	FILE *fp = NULL;
	int filesize = 0, readsize = 0;

	if(!filename || !mode || !buf || bufSize < 0) return -1;
	
	filesize = sw_file_getSize(filename);
	if(filesize < 0) return -1;
	else if(filesize == 0) return 0;

	fp = fopen(filename, mode);
	if(!fp) return -1;
	if(filesize > bufSize) readsize = -1;
	else readsize = fread(buf, sizeof(char), filesize, fp);
	fclose(fp);

	return readsize;
}

/* 更新文件 */
int sw_file_update(const char *filename, const char *mode, const char *buf, int bufSize)
{
	FILE *fp = NULL;
	int writesize = 0;

	if(!filename || !mode || !buf || bufSize < 0) return -1;

	fp = fopen(filename, mode);
	if(!fp) return -1;
	if(bufSize > 0) writesize = fwrite(buf, sizeof(char), bufSize, fp);
	fclose(fp);

	return writesize;
}

/* 得到文件大小 */
int sw_file_getSize(const char *filename)
{
	struct stat statBuf = { 0 };

	if(!filename) return -1;

	if(stat(filename, &statBuf) == 0) return statBuf.st_size;
	else return -1;
}

/* 重命名文件 */
int sw_file_rename(const char *oldName, const char *newName)
{
	return rename(oldName, newName);	
}

/* 拷贝文件 */
int sw_file_copy(const char *existingFilename, const char *newFilename, bool failIfExists)
{
	char *pBuf = NULL;
	int filesize = 0;

	if(!existingFilename || !newFilename || (failIfExists && sw_file_exists(newFilename))) return -1;

	filesize = sw_file_getSize(existingFilename);
	if(filesize < 0) return -1;

	pBuf = (char *)malloc(filesize);
	if(!pBuf) return -1;
	if(sw_file_load(existingFilename, "rb", pBuf, filesize) != filesize || \
	   sw_file_update(newFilename, "wb", pBuf, filesize) != filesize) filesize = -1;
	free(pBuf);

	return filesize;
}

/* 删除文件 */
int sw_file_delete(const char *filename)
{
	return remove(filename);	
}

/* 判断文件是否存在 */
bool sw_file_exists(const char *filename)
{
	if(access(filename, 0) == 0) return true;
	else return false;
}

/* 读配置或字典文件(mode : "GetFieldName", 根据"字段值"获取"字段名"; "GetFieldValue", 根据"字段名"获取"字段值") */
char *sw_file_getCfgString(const char *filename, const char *section, const char *mode, char *field, char *value, int resultBufSize)
{
	char *pBuf = NULL, *pSection = NULL, *pStr = NULL;
	int filesize = 0;

	if(!filename || !mode || !field || !value || resultBufSize <= 0) return NULL;

	filesize = sw_file_getSize(filename);
	if(filesize <= 0) return NULL;

	pBuf = (char *)malloc(filesize+1);
	if(!pBuf) return NULL;
	if(sw_file_load(filename, "rb", pBuf, filesize) != filesize) goto EndP;
	else pBuf[filesize] = '\0';

	if(section)
	{
	    pSection = xstrcasestr(pBuf, "left", section);
	    if(!pSection) goto EndP;
	}
	else pSection = pBuf;

	if(xstrcasecmp(mode, "GetFieldName") == 0)
	    pStr = sw_str_getFieldName(pSection, filesize-(pSection-pBuf), 0, field, resultBufSize, value);
	else if(xstrcasecmp(mode, "GetFieldValue") == 0)
	    pStr = sw_str_getFieldValue(pSection, filesize-(pSection-pBuf), 0, field, value, resultBufSize);

EndP:
	free(pBuf);
	return pStr;
}

/* 写配置或字典文件(mode : "SetFieldName", 根据"字段值"设置"字段名"; "SetFieldValue", 根据"字段名"设置"字段值") */
bool sw_file_setCfgString(const char *filename, const char *section, const char *mode, const char *field, const char *value, bool autoAdd)
{
	char *pBuf = NULL, *pSection = NULL;
	int filesize = 0, varysize1 = 0, varysize2 = 0;
	bool bRet = false;

	if(!filename || !mode || !field || !value) return false;

	filesize = sw_file_getSize(filename);
	if(filesize < 0) filesize = 0;

	pBuf = (char *)malloc(filesize+MAX_LINE_CHARS*2);
	if(!pBuf) return false;
	if(filesize > 0 && sw_file_load(filename, "rb", pBuf, filesize) != filesize) goto EndP;
	memset(pBuf+filesize, 0, MAX_LINE_CHARS*2);

	if(section)
	{
	    pSection = xstrcasestr(pBuf, "left", section);
	    if(!pSection)
	    {
	        if(autoAdd && (strlen(section)+4) <= MAX_LINE_CHARS)
	        {
	            pSection = pBuf+filesize;
	            sprintf(pSection, "\r\n%s\r\n", section);
	            varysize1 = strlen(section)+4;
	        }
	        else goto EndP; 
	    }
	}
	else pSection = pBuf;

	if((strlen(field)+strlen(value)) > MAX_LINE_CHARS) goto EndP;

	if(xstrcasecmp(mode, "SetFieldName") == 0)
	{
	    bRet = sw_str_setFieldName(pSection, filesize+MAX_LINE_CHARS*2-(pSection-pBuf), 0, field, value, autoAdd, &varysize2);
	    if(!bRet) goto EndP;
	}
	else if(xstrcasecmp(mode, "SetFieldValue") == 0)
	{
	    bRet = sw_str_setFieldValue(pSection, filesize+MAX_LINE_CHARS*2-(pSection-pBuf), 0, field, value, autoAdd, &varysize2);
	    if(!bRet) goto EndP;
	}

	if(bRet) bRet = (sw_file_update(filename, "wb", pBuf, filesize+varysize1+varysize2) == filesize+varysize1+varysize2);

EndP:
	free(pBuf);
	return bRet;
}

/* 从配置或字典文件中删除(mode : "DelFieldByName", 根据"字段名"删除该"字段"; "DelFieldByValue", 根据"字段值"删除该"字段") */
bool sw_file_delCfgString(const char *filename, const char *section, const char *mode, const char *field, const char *value)
{
	char *pBuf = NULL, *pSection = NULL;
	int filesize = 0, varysize = 0;
	bool bRet =  false;

	if(!filename || !mode || (!field && !value)) return false;

	filesize = sw_file_getSize(filename);
	if(filesize < 0) return false;
	else if(filesize == 0) return true;

	pBuf = (char *)malloc(filesize+1);
	if(!pBuf) return false;
	if(sw_file_load(filename, "rb", pBuf, filesize) != filesize) goto EndP;
	else pBuf[filesize] = '\0';

	if(section)
	{
	    pSection = xstrcasestr(pBuf, "left", section);
	    if(!pSection) { bRet = true; goto EndP; }
	}
	else pSection = pBuf;

	if(xstrcasecmp(mode, "DelFieldByName") == 0)
	{
	    bRet = sw_str_delFieldByName(pSection, filesize-(pSection-pBuf), 0, field, &varysize);
	    if(!bRet) goto EndP;
	}
	else if(xstrcasecmp(mode, "DelFieldByValue") == 0)
	{
	    bRet = sw_str_delFieldByValue(pSection, filesize-(pSection-pBuf), 0, value, &varysize);
	    if(!bRet) goto EndP;
	}

	if(bRet) bRet = (sw_file_update(filename, "wb", pBuf, filesize+varysize) == filesize+varysize);

EndP:
	free(pBuf);
	return bRet;
}
