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

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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

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

#include "cmunipack.h"
#include "config.h"
#include "utils.h"
#include "cmdline.h"
#include "cfgfile.h"

/* Standard strings */
#define WARRANTYLINE 	"This program is free but without warranty; see the software license for details.\n"
#define COPYRIGHTLINE 	"Copyright 2024 David Motl, Czech republic\n"
#define PROJECTLINE 	"This program is a part of the C-Munipack project.\n"
#define HOMEPAGELINE 	"Home page: http://c-munipack.sourceforge.net/\n"
#define BUGREPORTS 		"Bug reports: David Motl <dmotl@volny.cz>\n"

/* Toolkit errors */
static char *tools_formaterror(int status)
{
	char buf[MAXLINE];

  	switch (status) 
	{
	case CMPACK_ERR_CMDLINE_ERROR:
	    return cmpack_strdup("Syntax error in command line parameters");
	case CMPACK_ERR_CANT_OPEN_DIRFILE:
	    return cmpack_strdup("Cannot open list of input files");
	case CMPACK_ERR_CANT_MAKE_DIRFILE:
	    return cmpack_strdup("Cannot open list of output files");
	case CMPACK_ERR_CFG_OPEN_ERROR:
	    return cmpack_strdup("Configuration file not found");
	case CMPACK_ERR_CFG_READ_ERROR:
	    return cmpack_strdup("Syntax error in configuration file");
	case CMPACK_ERR_INVALID_ROTATION:
		return cmpack_strdup("Invalid value of image rotation");
	case CMPACK_ERR_NO_TIME_CORRECTION:
		return cmpack_strdup("Missing value of time correction");
	case CMPACK_ERR_INVALID_FILE_MASK:
		return cmpack_strdup("Invalid syntax of output file mask");
	case CMPACK_ERR_INVALID_OUT_FILE:
		return cmpack_strdup("Invalid syntax of output file path");
    default:
		sprintf(buf, "Unknown error status %d", status);
		return cmpack_strdup(buf);
	}
}

/* Clean program info */
void Init(AppInfo *cmd)
{
	cmpack_init();
	cmdline_init(cmd);
	cfgfile_init(cmd);
}

/* Clean program info */
void Clean(AppInfo *cmd)
{
	cmdline_clean(cmd);
	cfgfile_clean(cmd);
	cmpack_cleanup();
}

/* Prints short version of GPL license to the stdout */
void PrintLicense(AppInfo *cmd)
{
	PrintVersion(cmd);
	printf("\nThis program is free software; you can redistribute it and/or modify\n");
	printf("it under the terms of the GNU General Public License, version 2\n");
	printf("as published by the Free Software Foundation.\n\n");
	printf("This program is distributed in the hope that it will be useful\n");
	printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
	printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
	printf("GNU General Public License for more details.\n");
	printf("You should have received a copy of the GNU General Public License\n");
	printf("along with this program; if not, write to the Free Software\n");
	printf("Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n");
}

/* Print version information */
void PrintVersion(AppInfo *cmd)
{
	if (cmdline_isdef(cmd, "quiet")==0 || cmdline_isdef(cmd, "version")!=0)
		printf("%s (%s) version %s\n", cmd->program->name, CMAKE_PROJECT_NAME, VERSION);
}

/* Print help */
void PrintHelp(AppInfo *cmd)
{
	int i;

	PrintVersion(cmd);
	printf("%s\n", cmd->program->description);
	printf(PROJECTLINE);
	printf(COPYRIGHTLINE);
	printf("\nUsage:\n\t%s", cmd->program->name);
	if (cmd->options)
		printf(" [options]");
	if (cmd->params) {
		for (i=0; cmd->params[i].name!=NULL; i++) {
			printf(" %s", cmd->params[i].name);
			if (cmd->params[i].type == CMD_PTYPE_FILELIST)
				printf(" ...");
		}
	}
	printf("\n\n");
	cmdline_help(cmd);
	cfgfile_help(cmd);
	printf(WARRANTYLINE);
	printf(HOMEPAGELINE);
	printf(BUGREPORTS);
}

/* Print program prologue */
void PrintPrologue(AppInfo *cmd)
{
	PrintVersion(cmd);
	if (cmdline_isdef(cmd, "verbose")) {
		fprintf(stderr, "--------------------------------------------\n");
		cmdline_dump(cmd);
	}
	printf("\n");
}

/* Default callback function which prints messages to stdout. */
void PrintMessage(const char *msg, void *data)
{
	fprintf(stderr, "%s\n", msg);
}

/* Print program epilogue */
void PrintEpilogue(AppInfo *cmd, int in_files)
{
	if (!cmdline_isdef(cmd, "quiet")) {
		if (in_files<=0)
			fprintf(stderr, "\n%s: No input files. (Try '%s --help')\n", cmd->program->name, cmd->program->name);
		else
			fprintf(stderr, "\n%s: %d file(s) processed.\n", cmd->program->name, in_files);
	}
}

/* Print program epilogue */
void PrintEpilogueEx(AppInfo *cmd, int in_files, int out_files)
{
	if (!cmdline_isdef(cmd, "quiet")) {
		if (in_files<=0)
			fprintf(stderr, "\n%s: No input files. (Try '%s --help')\n", cmd->program->name, cmd->program->name);
		else if (in_files==out_files)
			fprintf(stderr, "\n%s: %d file(s) succeeded.\n", cmd->program->name, out_files);
		else
			fprintf(stderr, "\n%s: %d file(s) succeeded, %d file(s) failed.\n", cmd->program->name, out_files, in_files-out_files);
	}
}


/* Prints human readable form of error code to the specified file */
void PrintError(AppInfo *cmd, const char *afile, int aline, int status)
{
	char *buf;
	const char *program = cmd->program->name;

	if (status<2000)
		buf = cmpack_formaterror(status);
	else
		buf = tools_formaterror(status);
	if (!afile)
		fprintf(stderr,"%s:%s\n", program, buf);
	else if (!aline) 
		fprintf(stderr,"%s:%s:%s\n", program, afile, buf);
	else 
		fprintf(stderr,"%s:%s:%d:%s\n", program, afile, aline, buf);
	cmpack_free(buf);
}

/* Check syntax of file path */
int CheckFilePath(char *fpath)
{
	char *ptr;

	if (!fpath || *fpath=='\0')
		return 0;

	for (ptr=fpath; *ptr!=0; ptr++) {
#ifdef _WIN32
		if (*ptr=='/')
			*ptr = '\\';
#else
		if (*ptr=='\\')
			*ptr = '/';
#endif
	}
	return 1;
}

/* Check syntax of file mask */
int CheckFileMask(char *fmask)
{
	char *ptr;

	if (!fmask || *fmask=='\0')
		return 0;

	for (ptr=fmask; *ptr!=0; ptr++) {
#ifdef _WIN32
		if (*ptr=='/')
			*ptr = '\\';
#else
		if (*ptr=='\\')
			*ptr = '/';
#endif
	}
	return 1;
}

#ifdef _WIN32

void MakeInputName(char *buf, int buflen, const char *searchpath, const char *filename)
{
	char *ptr;
	
	ptr = strrchr(searchpath, '\\');
	if (ptr) {
		strcpy(buf, searchpath);
		buf[ptr-searchpath+1] = '\0';
		strcat(buf, filename);
	} else {
		strcpy(buf, filename);
	}
}

#endif

void FormatOutputName(char *buf, int buflen, const char *mask, const char *infile, int index)
{
	const char *sptr, *ext;
	int i, len;
	char format[64];

	buf[0] = '\0';

	i = 0;
	for (sptr=mask; *sptr!=0 && i<buflen-1; sptr++) {
		switch (*sptr)
		{
		case '%':
			/* Copy name of the source file (without extesion) */
			ext = strrchr(infile, '.');
			len = (int)(ext!=NULL ? (ext-infile) : strlen(infile));
			if (len>buflen-i-1)
				len = buflen-i-1;
			memcpy(buf+i, infile, len);
			i+=len;
			break;

		case '?':
			/* Replace question marks by index */
			len = 0;
			while (*sptr=='?') {
				len++;               /* len = number of ? marks */
				sptr++;
			}
			if (len>buflen-i-1)
				len = buflen-i-1;
			sprintf(format,"%%0%dd",len);
			i+=sprintf(buf+i, format, index);
			sptr--;
			break;

#ifdef _WIN32
		case '/':
			buf[i++] = '\\';
			break;
#else
		case '\\':
			buf[i++] = '/';
			break;
#endif

		default:
			buf[i++] = *sptr;
		}
    }
	buf[i] = '\0';
}

/* Convert string to array of integers */
int StrToIntV(const char *str, int **intv, int *intc)
{
	int	i, count, *buf;
	const char *ptr, *endptr;

	ptr = str;
	count = 0;
	while (*ptr!=0) {
		count++;
		ptr += strcspn(ptr, ",");
		if (*ptr!='\0')
			ptr++;
	}

	buf = malloc(count*sizeof(int));
	if (buf) {
		ptr = str;
		i = 0;
		while (*ptr!=0 && i<count) {
			buf[i++] = strtol(ptr, (char**)&endptr, 10);
			if (*endptr=='\0')
				break;
			ptr = endptr + strcspn(endptr, ",");
			if (*ptr!='\0')
				ptr++;
		}
		*intv = buf;
		*intc = i;
	}
	return 1;
}

/* Convert string to array of integers */
int StrToDoubleV(const char *str, double **dblv, int *dblc)
{
	int	i, count;
	double *buf;
	const char *ptr, *endptr;

	ptr = str;
	count = 0;
	while (*ptr!=0) {
		count++;
		ptr += strcspn(ptr, ",");
		if (*ptr!='\0')
			ptr++;
	}

	buf = malloc(count*sizeof(double));
	if (buf) {
		ptr = str;
		i = 0;
		while (*ptr!=0 && i<count) {
			buf[i++] = strtod(ptr, (char**)&endptr);
			if (*endptr=='\0')
				break;
			ptr = endptr + strcspn(endptr, ",");
			if (*ptr!='\0')
				ptr++;
		}
		*dblv = buf;
		*dblc = i;
	}
	return 1;
}

void ChangeFileExt(char *outf, const char *inf, const char *ext)
/* Changes extension in file name */
{
	char *x;
	strcpy(outf,inf);
	x = strrchr(outf,'.');
	if (x!=NULL)
		x[0] = 0;
    strcat(outf,".");
	strcat(outf,ext);
}

/* Check syntax of parameter */
int StrToKeyVal(const char *param, char **key, char **val)
{
	if (key) *key = NULL;
	if (val) *val = NULL;

	if (param) {
		const char *ptr = strchr(param, '=');
		if (ptr) {
			/* Long option with attribute value */
			int namelen = (int)(ptr-param), vallen = (int)strlen(ptr+1);
			if (namelen>0 || vallen>0) {
				if (key) {
					*key = (char*)malloc((namelen+1)*sizeof(char));
					if (*key) {
						memcpy(*key, param, (namelen)*sizeof(char));
						(*key)[namelen] = '\0';
					}
				}
				if (val) {
					*val = (char*)malloc((vallen+1)*sizeof(char));
					if (*val) {
						memcpy(*val, ptr+1, (vallen)*sizeof(char));
						(*val)[vallen] = '\0';
					}
				}
				return 1;
			}
		}
	}
	return 0;
}

/* Make copy of a string */
char *StrDup(const char *str)
{
	char *buf;
	size_t len;

	if (!str)
		return NULL;

	len = strlen(str);
	buf = (char*)malloc((len+1)*sizeof(char));
	if (buf)
		strcpy(buf, str);
	return buf;
}
