//
//striip.c
//
//Provides functions for doing string operations that autmatically call imalloc, irealloc, ifree.
//
//
//Strings created by these function should be released after they are finished with by calling
//  stringFree(stringbuffer)
//
//Certain functions will automatically release certain strings passed to it. Each function that 
//  accepts strings as a parameter will list what arguments are release and which are kept.
//
//stringFree which handles the release of strings will not release strings that were not allocated
//by means other than striip.c functions and memiip.c functions
//
//These functions will accept NULL as input strings. These are treated as zero length strings.
//
//Unless stated otherwise these functions will never return NULL as a string.
//
//-UserX 2001/11/03
//

#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include "misc/compat.h"
#include "base/mem.h"
#include "base/str.h"


//allocate block of memory ready for strings by calling ximalloc(length + 1)
// [0] and [length] are zeroed automatically
//length of less that zero will be set to zero.
char *stringMake(int length) {
	char *membuffer;
	if(length < 0) {
		length = 0;
	}
	//membuffer = ximalloc(length + 1);
	membuffer = memAlloc(length + 1, "String", NULL);
	membuffer[0] = 0;
	membuffer[length] = 0;
	return membuffer;
}

//resizes a string buffer, to a certain buffer size.
// a NULL is passed instead of a string  stringMake will be called instead
// [length] is zeroed automatically.
char *stringResize(char *dstbuffer, int length) {
	if(dstbuffer == NULL) {
		return stringMake(length);
	}

	//if(findmemtagbybuffer(dstbuffer) == -1) {
	if(memUnknown(dstbuffer)) {
		dstbuffer = stringCopy(dstbuffer);
	}

	if(length < 0) {
		length = 0;
	}
	//dstbuffer = xirealloc(dstbuffer, length + 1);
	dstbuffer = memResize(dstbuffer, length + 1);
	dstbuffer[length] = 0;
	return dstbuffer;
}


//Releases a string buffer created by any other string function.
//simply just calls sifree thus only functions that
void stringFree(char *dstbuffer) {
	if(dstbuffer != NULL) {
		//sifree(dstbuffer);
		memSafeFree(dstbuffer);
	}
}

//returns a zerolength string.
char *stringBlank() {
	//char *membuffer;
	//membuffer = stringMake(0); //ximalloc(1);
	////membuffer[0] = 0;
	//return membuffer;
	return stringMake(0);
}

//test if a string is a NULL or zero length.
int isStringBlank(char *srcbuffer) {
	return (srcbuffer == NULL) || (strlen(srcbuffer) == 0);
}

//create a string by copying an existing one.
//if srcbuffer is NULL it will create zero length string
//releases:	none
//keeps:	srcbuffer
char *stringCopy(char *srcbuffer) {
	char *membuffer;
	if(srcbuffer == NULL) {
		return stringBlank();
	} 
	
	membuffer = stringMake(strlen(srcbuffer));//ximalloc(strlen(srcbuffer) + 1);
	strcpy(membuffer, srcbuffer);
	return membuffer;
}

//releases dstbuffer and returns a copy of srcbuffer
char *stringReplace(char *dstbuffer, char *srcbuffer) {
	if(dstbuffer != NULL) {
		stringFree(dstbuffer);
	}
	return stringCopy(srcbuffer);
}

//check if a string is actually one of ours.
//if so. return the string point
//if not. create a copy and return copy's pointer
//releases:	none
//keeps:	srcbuffer
char *stringCopyIfForeign(char *srcbuffer){
	//if(findmemtagbybuffer(srcbuffer) == -1) {
	if(memUnknown(srcbuffer)) {
		return stringCopy(srcbuffer);
	}
	return srcbuffer;
}

//create a string by copying a subsection of an existing string.
//function pays attention to the actually length of srcbuffer
//if srcbuffer is NULL it will return a zero length.
//releases:	none
//keeps:	srcbuffer
char *stringCopyPart(char *srcbuffer, int start, int length) {
	char *membuffer;
	int l;

	l = strlen(srcbuffer);
	if(srcbuffer == NULL) {
		return stringBlank();
	}

	if(start < 0) {
		start = 0;
	}
	if(start >= l) {
		return stringBlank();
	}
	if(l - start < length) {
		length = l - length;
	}
	membuffer = stringMake(length); //ximalloc(length + 1);
	//membuffer[length] = 0;
	memcpy(membuffer, srcbuffer + start, length);
	return membuffer;
}


//Append string srcbuffer to string dstbuffer. Returns the new pointer for dstbuffer.
//if dstbuffer or srcbuffer are NULL they are treated as zero length strings
//releases:	dstbuffer
//keeps:	srcbuffer
char *stringAppend(char *dstbuffer, char *srcbuffer) {
	if(dstbuffer == NULL) {
		dstbuffer = stringBlank(); //make into a zerolength string
	}
	if(isStringBlank(srcbuffer)) {
		return stringCopyIfForeign(dstbuffer);
	}
	dstbuffer = stringResize(dstbuffer, strlen(dstbuffer) + strlen(srcbuffer));//xirealloc(dstbuffer, strlen(dstbuffer) + strlen(srcbuffer) + 1);
	strcpy(dstbuffer + strlen(dstbuffer), srcbuffer);
	return dstbuffer;
}

//Does the same as stringAppend except dstbuffer is the second argument instead.
//releases:	dstbuffer
//keeps:	srcbuffer
char *stringAppend2(char *srcbuffer, char *dstbuffer) {
	if(dstbuffer == NULL) {
		dstbuffer = stringBlank(); //make into a zerolength string
	}
	if(isStringBlank(srcbuffer)) {
		return stringCopyIfForeign(dstbuffer);
	}
	dstbuffer = stringResize(dstbuffer, strlen(dstbuffer) + strlen(srcbuffer)); //xirealloc(dstbuffer, strlen(dstbuffer) + strlen(srcbuffer) + 1);
	memmove(dstbuffer + strlen(srcbuffer), dstbuffer, strlen(dstbuffer) + 1);
	memcpy(dstbuffer, srcbuffer, strlen(srcbuffer));
	return dstbuffer;
}

//joins three strings together. the middle string is used as the destination.
//releases:	dstbuffer
//keeps:	src1buffer, src2buffer
char *stringAppend3(char *src1buffer, char *dstbuffer, char *src2buffer) {
	//todo: fix this so it's not quick dirty.
	return stringAppend2(src1buffer, stringAppend(dstbuffer, src2buffer));
}

//does the same as stringAppend except the srcbuffer is released.
//releases:	dstbuffer, srcbuffer
//keeps:	none
char *stringJoin(char *dstbuffer, char *srcbuffer) {
	dstbuffer = stringAppend(dstbuffer, srcbuffer);
	stringFree(srcbuffer);
	return dstbuffer;
}

//concats a series of strings together. the list must terminated with a NULL.
//all input strings will be released when finished with.
//releases:	all
//keeps:	none
char *stringJoinMany(char *srcbuffer, ...) {
	char *dstbuffer, *vabuffer;
	int l;
	int m;
	int i;
	va_list marker;
	

	if(srcbuffer == NULL) {
		return stringBlank();
	}

	l = strlen(srcbuffer);


	va_start( marker, srcbuffer );	/* Initialize variable arguments. */
	while(1) {
		vabuffer = va_arg( marker, char *);
		if(vabuffer == NULL) {
			break;
		}
		l += strlen(vabuffer);
	}
	va_end( marker );		/* Reset variable arguments.      */

	
	va_start( marker, srcbuffer );	/* Initialize variable arguments. */

	dstbuffer = stringResize(srcbuffer, l);//xirealloc(srcbuffer, l + 1);
	//dstbuffer[l] = 0;
	i = strlen(dstbuffer);
	while(1) {
		vabuffer = va_arg( marker, char *);
		if(vabuffer == NULL) {
			break;
		}
		m = strlen(vabuffer);
		memcpy(dstbuffer + i, vabuffer, m);
		stringFree(vabuffer);
		i += m;
	}
	va_end( marker );		/* Reset variable arguments.      */

	return dstbuffer;

}


//concats a series of strings together. the list must terminated with a NULL.
//all input strings will be kept when finished with.
//releases:	none
//keeps:	all
char *stringCopyMany(char *srcbuffer, ...) {
	char *dstbuffer, *vabuffer;
	int l;
	int m;
	int i;
	va_list marker;
	

	if(srcbuffer == NULL) {
		return stringBlank();
	}

	l = strlen(srcbuffer);


	va_start( marker, srcbuffer );	/* Initialize variable arguments. */
	while(1) {
		vabuffer = va_arg( marker, char *);
		if(vabuffer == NULL) {
			break;
		}
		l += strlen(vabuffer);
	}
	va_end( marker );		/* Reset variable arguments.      */

	
	va_start( marker, srcbuffer );	/* Initialize variable arguments. */

	dstbuffer = stringResize(stringCopy(srcbuffer), l);//xirealloc(srcbuffer, l + 1);
	//dstbuffer[l] = 0;
	i = strlen(dstbuffer);
	while(1) {
		vabuffer = va_arg( marker, char *);
		if(vabuffer == NULL) {
			break;
		}
		m = strlen(vabuffer);
		memcpy(dstbuffer + i, vabuffer, m);
		i += m;
	}
	va_end( marker );		/* Reset variable arguments.      */

	return dstbuffer;

}
	

   

//creates a string representation of an int
char *intToString(int i) {
	char *membuffer;
	int l = 0;
	int v = i;
	int s = (i < 0);
	do {
		v /= 10;
		l++;
	} while (v);
	if (s) {
		l++;
	}
	membuffer = stringMake(l);//ximalloc(l + 1);
		
	//membuffer[l] = 0;
	if(s) {
		membuffer[0] = '-';
		for (l--; l >= 1; l--) {
			membuffer[l] = (char) ('0' + (-(i % 10)));
			i /= 10;
		}
	} else {
		for (l--; l >= 0; l--) {
			membuffer[l] = (char) ('0' + (i % 10));
			i /= 10;
		}
	}
	return membuffer;
}

char *intToStringPadded(unsigned int i, char c, int l) {
	char *membuffer;
	membuffer = stringMake(l); //ximalloc(l + 1);
	//membuffer[l] = 0;
	membuffer[l - 1] = (char) ('0' + (i % 10));
	i /= 10;
	for (l -= 2; l>=0; l --) {
		if(i == 0) {
			membuffer[l] = c;
		} else {
			membuffer[l] = (char) ('0' + (i % 10));
			i /= 10;
		}
		
	}
	return membuffer;
}

char intToHexChar(int v) {
	v &= 0xf;
	return (char) ((v < 10) ? v + '0' : v - 10 + 'a');
}

//converts a number to the format: 0x12345678
char *intToHexString(int v) {
	int i;
	char *membuffer = stringMake(2 + sizeof(int) * 2);
	membuffer[0] = '0';
	membuffer[1] = 'x';

	for(i = 2 + sizeof(int) * 2 - 1; i >= 2; i--) {
		membuffer[i] = intToHexChar(v);
		v >>= 4;
	}
	return membuffer;
}

char *ptrToString(void *p) {
	if(p == NULL) {
		return stringCopy("-<<NULL>>-");
	}
	return intToHexString((int) p);
}

char *bufferToHexString(uint8 *buf, int length) {
	int i;
	char *membuffer = stringMake(2 * length);
	for(i = 0; i < length; i++) {
		membuffer[i * 2] = intToHexChar(buf[i] >> 4);
		membuffer[i * 2 + 1] = intToHexChar(buf[i]);
	}
	return membuffer;
}

//Creates a string of the format: YYYY/MM/DD-HH:MM:SS
char *stringDateTime(time_t datetime) {
	struct tm *t = gmtime(&datetime);
	if(t == NULL) {
		return stringAppend(intToString((int) datetime), " is a bad datetime stamp");
	}
	
	return stringJoinMany(
					intToStringPadded(t->tm_year + 1900, '0', 4), "/",
					intToStringPadded(t->tm_mon + 1,  '0', 2), "/",
					intToStringPadded(t->tm_mday, '0', 2), "-",
					intToStringPadded(t->tm_hour, '0', 2), ":",
					intToStringPadded(t->tm_min,  '0', 2), ":",
					intToStringPadded(t->tm_sec, '0', 2),
					NULL);
}

//Trims the start and finish of and of the characters in the string what.
//Releases: dstbuffer
//Keeps: what
char *stringTrim(char *dstbuffer, char *what) {
	int i;//, j;
	int l = 0; //lw

	if(dstbuffer == NULL) {
		return stringBlank();
	}
	if(what == NULL) {
		return stringCopyIfForeign(dstbuffer);
	}
	//lw = strlen(what);
	for(i = 0; dstbuffer[i] != 0; i++) {
		if(strchr(what, dstbuffer[i]) != NULL) {
//		for(j = 0; j < lw; j++) {
//			if(dstbuffer[i] == what[j]) {
			l++;
			dstbuffer[i] = 0;
//			}
//		}
		}
		if (dstbuffer[i] != 0) {
			break;
		}
	}
	if(l) { //shuffle it to the front of the buffer
		memmove(dstbuffer, dstbuffer + l, strlen(dstbuffer + l) + 1);
	}
	for (i = strlen(dstbuffer) - 1; i >= 0; i--) {
		if(strchr(what, dstbuffer[i]) != NULL) {
//		for(j = 0; j < lw; j++) {
//			if(dstbuffer[i] == what[j]) {
			l++;
			dstbuffer[i] = 0;
//			}
//		}
		}
		if (dstbuffer[i] != 0) {
			break;
		}
	}
	if(l) {
		dstbuffer = stringResize(dstbuffer, strlen(dstbuffer));
	}
	return dstbuffer;
}

//Searches a string for split. returns a pointer to a string of what's to the left
//of split. Srcbuffer will be modified to hold only what is right of split.
//If split is NULL or blank then it will return a blank string with srcbuffer
//unmodified.
//If split is not found it will return a copy of src buffer. And srcbuffer 
//will be blanked.
//Releases: none
//Modifies: srcbuffer
//Keeps: what
char *stringSplit(char *srcbuffer, char *split) {
	char *s;
	char *c;
	int i;
	if(srcbuffer == NULL) {
		return stringBlank();
	}
	if(isStringBlank(split)) {
		return stringBlank();
	}
	c = strstr(srcbuffer, split);
	if(c == NULL) {
		s = stringCopy(srcbuffer);
		srcbuffer[0] = 0;
		return s;
	}
	s = stringCopyPart(srcbuffer, 0, c - srcbuffer);
	i = (c - srcbuffer) + strlen(split);
	memmove(srcbuffer, srcbuffer + i, strlen(srcbuffer) - i + 1);
	return s;
}


//Performs a case sensitive compare
//Releases: None
//Modifies: None
//Keeps: All
int stringCompare(char *buffer1, char *buffer2) {
	if(isStringBlank(buffer1)) {
		if(isStringBlank(buffer2)) {
			return 0;
		} else {
			return -1;
		}
	} else {
		if(isStringBlank(buffer2)) {
			return 1;
		} else {
			return strcmp(buffer1, buffer2);
		}
	}
}

//Performs a case insensitive compare
//Releases: None
//Modifies: None
//Keeps: All
int stringCaseCompare(char *buffer1, char *buffer2) {
	if(isStringBlank(buffer1)) {
		if(isStringBlank(buffer2)) {
			return 0;
		} else {
			return -1;
		}
	} else {
		if(isStringBlank(buffer2)) {
			return 1;
		} else {
			return strcasecmp(buffer1, buffer2);
		}
	}
}

int stringLength(char *buffer) {
	if(buffer == NULL) {
		return 0;
	}
	return strlen(buffer);
}

/**
Converts a string to all uppercase, will copy the string if it is 'foreign'. 
@param buffer The string to modify.
@return Pointer to the string if it was copied.
*/
char *stringToUpper(char *buffer) {
	size_t i;
	buffer = stringCopyIfForeign(buffer);
	for(i = 0; i < strlen(buffer); i++) {
		buffer[i] = (char) toupper(buffer[i]);
	}
	return buffer;
}

/**
Converts a string to all lowercase, will copy the string if it is 'foreign'. 
@param buffer The string to modify.
@return Pointer to the string if it was copied.
*/
char *stringToLower(char *buffer) {
	size_t i;
	buffer = stringCopyIfForeign(buffer);
	for(i = 0; i < strlen(buffer); i++) {
		buffer[i] = (char) tolower(buffer[i]);
	}
	return buffer;
}

