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

context.c (C-Munipack project)
Context related functions
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 "cmpack_common.h"
#include "console.h"

struct _CmpackConsole
{
	int refcnt;						/**< Reference counter */
	int quiet;						/**< Supress messages except error reports */
	int debug;						/**< Be verbose - for debugging purposes */
	CmpackPrint *print;				/**< Output callback procedure */
};

struct _CmpackConsoleStream
{
	CmpackConsole gc;
	FILE *stream;
};
typedef struct _CmpackConsoleStream CmpackConsoleStream;

struct _CmpackConsoleCB
{
	CmpackConsole gc;
	CmpackCallbackType *cbproc;
	void *cbdata;
};
typedef struct _CmpackConsoleCB CmpackConsoleCB;

static void cmpack_print_stream(CmpackConsoleStream *con, const char *msg)
{
	fprintf(con->stream, "%s\n", msg);
}

static void cmpack_print_cb(CmpackConsoleCB *con, const char *msg)
{
	if (con->cbproc)
		con->cbproc(msg, con->cbdata);
}

/* Create and initialize the context */
CmpackConsole *cmpack_con_init(void)
{
	CmpackConsoleStream *con = (CmpackConsoleStream*)cmpack_calloc(1, sizeof(CmpackConsoleStream));
	con->gc.refcnt = 1;
	con->gc.print = (CmpackPrint*)&cmpack_print_stream;
	con->stream = stderr;
	return (CmpackConsole*)con;
}

/* Create and initialize the context */
CmpackConsole *cmpack_con_reference(CmpackConsole *ctx)
{
	ctx->refcnt++;
	return ctx;
}

/* Create and initialize the context */
void cmpack_con_destroy(CmpackConsole *ctx)
{
	if (ctx) {
		ctx->refcnt--;
		if (ctx->refcnt==0) 
			cmpack_free(ctx);
	}
}

/* Sets output level */
CmpackConsole *cmpack_con_init_cb(CmpackCallbackType *cbproc, void *cbdata)
{
	CmpackConsoleCB *con = (CmpackConsoleCB*)cmpack_calloc(1, sizeof(CmpackConsoleCB));
	con->gc.refcnt = 1;
	con->gc.print = (CmpackPrint*)&cmpack_print_cb;
	con->cbproc = cbproc;
	con->cbdata = cbdata;
	return (CmpackConsole*)con;
}

/* Sets output level */
void cmpack_con_set_level(CmpackConsole *ctx, CmpackOutputLevel level)
{
	ctx->quiet = level<=CMPACK_LEVEL_QUIET;
	ctx->debug = level>=CMPACK_LEVEL_DEBUG;
}

int is_debug(CmpackConsole *ctx)
{
	if (ctx)
		return ctx->debug;
	return 0;
}

/* Print message to callback function */
void printout(CmpackConsole *ctx, int debug, const char *message)
{
	if (ctx) {
		if (!ctx->quiet && (!debug || ctx->debug))
			ctx->print(ctx, message);
	}
}

/* Format error message and print it to callback function */
void printerr(CmpackConsole *ctx, int error)
{
	char *message;

	if (ctx) {
		if (!ctx->quiet) {
			message = cmpack_formaterror(error);
			ctx->print(ctx, message);
			cmpack_free(message);
		}
	}
}

/* Print parameter value (integer) */
void printpari(CmpackConsole *ctx, const char *name, int valid, int value)
{
	char buf[128];

	if (ctx) {
		if (!ctx->quiet && ctx->debug) {
			if (valid)
				sprintf(buf, "\t%s = %d", name, value);
			else
				sprintf(buf, "\t%s = (undefined)", name);
			ctx->print(ctx, buf);
		}
	}
}

/* Print parameter value (double) */
void printpard(CmpackConsole *ctx, const char *name, int valid, double value, int prec)
{
	char buf[512];

	if (ctx) {
		if (!ctx->quiet && ctx->debug) {
			if (valid)
				sprintf(buf, "\t%s = %.*f", name, prec, value);
			else
				sprintf(buf, "\t%s = (undefined)", name);
			ctx->print(ctx, buf);
		}
	}
}

void printpars(CmpackConsole *ctx, const char *name, int valid, const char *value)
{
	char buf[512];

	if (ctx) {
		if (!ctx->quiet && ctx->debug) {
			if (!valid)
				sprintf(buf, "\t%s = (undefined)", name);
			else if (!value)
				sprintf(buf, "\t%s = (null)", name);
			else
				sprintf(buf, "\t%s = '%s'", name, value);
			ctx->print(ctx, buf);
		}
	}
}

/* Print parameter value (double) */
void printparvd(CmpackConsole *ctx, const char *name, int valid, int count, const double *values, int prec)
{
	int i;
	char buf[512];

	if (ctx) {
		if (!ctx->quiet && ctx->debug) {
			if (!valid) {
				sprintf(buf, "\t%s: (undefined)", name);
				ctx->print(ctx, buf);
			} else {
				if (count<=0)
					sprintf(buf, "\t%s: (empty)", name);
				else 
					sprintf(buf, "\t%s: %d item(s)", name, count);
				ctx->print(ctx, buf);
				for (i=0; i<count; i++) {
					sprintf(buf, "\t\t%.*f", prec, values[i]);
					ctx->print(ctx, buf);
				}
			}
		}
	}
}

/* Print parameter value (double) */
void printparvi(CmpackConsole *ctx, const char *name, int valid, int count, const int *values)
{
	int i;
	char buf[128];

	if (ctx) {
		if (!ctx->quiet && ctx->debug) {
			if (!valid) {
				sprintf(buf, "\t%s: (undefined)", name);
				ctx->print(ctx, buf);
			} else {
				if (count>0)
					sprintf(buf, "\t%s: %d item(s)", name, count);
				else
					sprintf(buf, "\t%s: (empty)", name);
				ctx->print(ctx, buf);
				for (i=0; i<count; i++) {
					sprintf(buf, "\t\t%d", values[i]);
					ctx->print(ctx, buf);
				}
			}
		}
	}
}
