/**************************************************************

comfun.c (C-Munipack project)
Common functions, macros, etc.
Copyright (C) 2003 David Motl, dmotl@volny.cz

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

**************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#include <limits.h>
#include <float.h>

#ifndef _WIN32
#include <sys/stat.h>
#include <sys/types.h>
#endif

#include "comfun.h"

int pixrange(int bitpix, double *minvalue, double *maxvalue)
{
	switch (bitpix) 
	{
	case CMPACK_BITPIX_SSHORT:
		if (minvalue) *minvalue = INT16_MIN;
		if (maxvalue) *maxvalue = INT16_MAX;
		return 1;
	case CMPACK_BITPIX_USHORT:
		if (minvalue) *minvalue = 0.0;
		if (maxvalue) *maxvalue = UINT16_MAX;
		return 1;
	case CMPACK_BITPIX_SLONG:
		if (minvalue) *minvalue = INT32_MIN;
		if (maxvalue) *maxvalue = INT32_MAX;
		return 1;
	case CMPACK_BITPIX_ULONG:
		if (minvalue) *minvalue = 0.0;
		if (maxvalue) *maxvalue = UINT32_MAX;
		return 1;
	case CMPACK_BITPIX_FLOAT:
		if (minvalue) *minvalue = FLT_MIN;
		if (maxvalue) *maxvalue = FLT_MAX;
		return 1;
	case CMPACK_BITPIX_DOUBLE:
		if (minvalue) *minvalue = DBL_MIN;
		if (maxvalue) *maxvalue = DBL_MAX;
		return 1;
	default:
		if (minvalue) *minvalue = 0.0;
		if (maxvalue) *maxvalue = 0.0;
		return 0;
	}
}

const char *pixformat(int bitpix)
{
	switch (bitpix) 
	{
	case CMPACK_BITPIX_SSHORT:
		return "Signed short int (2 bytes)";
	case CMPACK_BITPIX_USHORT:
		return "Unsigned short int (2 bytes)";
	case CMPACK_BITPIX_SLONG:
		return "Signed int (4 bytes)";
	case CMPACK_BITPIX_ULONG:
		return "Unsigned int (4 bytes)";
	case CMPACK_BITPIX_FLOAT:
		return "Single precision FP (4 bytes)";
	case CMPACK_BITPIX_DOUBLE:
		return "Double precision FP (8 bytes)";
	default:
		return "Unknown data format";
	}
}

static int iswhitespace(char ch)
{
	return (ch > 0 && ch <= ' ');
}

int needs_trim(const char *str)
{
	if (str && *str!='\0') {
		if (iswhitespace(*str) || iswhitespace(str[strlen(str)-1]))
			return 1;
	}
	return 0;
}

/* Trim leading and trailing white spaces */
char *trim(const char *str)
{
	return rtrim(ltrim(str));
}

/* Trim trailing white spaces */
char *rtrim(char *str)
{
	if (str) {
		char *ptr = str + strlen(str);
		while (ptr>str && iswhitespace(*(ptr-1)))
			ptr--;
		*ptr = '\0';
	}
	return str;
}

/* Trim leading white spaces */
char *ltrim(const char *str)
{
	size_t len;
	char *buf;

	if (str) {
		const char *ptr = str;
		while (*ptr!='\0' && iswhitespace(*ptr))
			ptr++;
		len = strlen(ptr);
		buf = (char*)cmpack_malloc((len+1)*sizeof(char));
		strcpy(buf, ptr);
		return buf;
	}
	return NULL;
}

/* Find string in a memory buffer */
const char *memstr(const char *c, char *s, size_t n)
{
	const char *p;
	size_t needlesize = strlen(s);
	for (p = c; p <= (c-needlesize+n); p++) {
		if (memcmp(p, s, needlesize) == 0)
			return p; /* found */
	}
	return NULL;
}

/* Encode string that it can be safely written to XML file */
char *xml_encode_string(const char *str)
{
	int len;
	const char *sptr;
	char *buf = NULL, *dptr;

	if (str) {
		/* Compute number of bytes needed to store the data */
		len = 0;
		for (sptr=str; *sptr!='\0'; sptr++) {
			char ch = *sptr;
			if (ch == '<' || ch == '>')
				len += 3;
			else if (ch=='&')
				len += 4;
			else if (ch<0 || ch>=' ')
				len += 1;
		}
		buf = (char*)cmpack_malloc((len+1)*sizeof(char));
		for (sptr=str, dptr=buf; *sptr!='\0'; sptr++) {
			char ch = *sptr;
			if (ch == '<') {
				memcpy(dptr, "&lt;", 3);
				dptr += 3;
			} else if (ch == '>') {
				memcpy(dptr, "&gt;", 3);
				dptr += 3;
			} else if (ch=='&') {
				memcpy(dptr, "&amp;", 4);
				dptr += 4;
			} else if (ch<0 || ch>=' ') 
				*dptr++ = ch;
		}
		*dptr = '\0';
	}
	return buf;
}

int strcpy_truncate(char *buf, int bufsize, const char *str)
{
	int len;

	if (bufsize<=0 || !buf)
		return 0;

	if (!str) {
		buf[0] = '\0';
		return 0;
	}
	
	len = (int)strlen(str);
	if (len>=bufsize)
		len = bufsize-1;
	memcpy(buf, str, len);
	buf[len] = '\0';
	return len;
}
