/*
 * Copyright (C) 2000, Matias Atria
 *
 * 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 <string.h>
#include <errno.h>
#include <ctype.h>

#include "mdvi.h"
#include "private.h"

char *_mdvi_fallback_font = NULL;

int	mdvi_get_pagesort(const char *spec)
{
	if(STRCEQ(spec, "up"))
		return MDVI_PAGE_SORT_UP;
	else if(STRCEQ(spec, "down"))
		return MDVI_PAGE_SORT_DOWN;
	else if(STRCEQ(spec, "random"))
		return MDVI_PAGE_SORT_RANDOM;
	else if(STRCEQ(spec, "dviup"))
		return MDVI_PAGE_SORT_DVI_UP;
	else if(STRCEQ(spec, "dvidown"))
		return MDVI_PAGE_SORT_DVI_DOWN;
	else if(STRCEQ(spec, "none"))
		return MDVI_PAGE_SORT_NONE;
	return -1;
}

int	mdvi_get_debugmask(const char *spec)
{
	const char *ptr, *text;
	static char *masks[] = {
		"opcodes", "fonts", 
		"files", "dvi", 
		"params", "special", 
		"device", "glyphs",
		"bitmaps", "paths",
		"search", "vars",
		"bitops", "bitdata",
		"type1", "tt",
		"ft2", "fontmaps"
	};
	int	done = 0;
	int	mask = 0;
	int	i;
	
	for(ptr = text = spec; !done; ptr++) {
		int	len;
		
		if(*ptr && *ptr != '|' && *ptr != ',')
			continue;
		if(*ptr == 0)
			done = 1;
		len = ptr - text;
		if(len == 0)
			continue;
		for(i = 0; masks[i]; i++) {
			if(STRNEQ(masks[i], text, len)) {
				mask |= (1 << i);
				break;
			}
		}
		if(!masks[i] && STRNEQ(text, "silent", len))
			mask |= DBG_SILENT;
		text = ptr + 1;				
	}
	return mask;
}

DviOrientation mdvi_getorient(const char *s)
{
	if(STRCEQ(s, "TBLR") || 
	   STRCEQ(s, "Portrait") || 
	   STRCEQ(s, "TopLeft") ||
	   STRCEQ(s, "top-left") ||
	   STRCEQ(s, "tl"))
		return MDVI_ORIENT_TBLR;
		
	if(STRCEQ(s, "TBRL") || 
	   STRCEQ(s, "TopRight") ||
	   STRCEQ(s, "top-right") ||
	   STRCEQ(s, "tr"))
		return MDVI_ORIENT_TBRL;
		
	if(STRCEQ(s, "BTLR") || 
	   STRCEQ(s, "BottomLeft") ||
	   STRCEQ(s, "bottom-left") ||
	   STRCEQ(s, "bl"))
		return MDVI_ORIENT_BTLR;
		
	if(STRCEQ(s, "BTRL") || 
	   STRCEQ(s, "BottomRight") ||
	   STRCEQ(s, "bottom-right") ||
	   STRCEQ(s, "br"))
		return MDVI_ORIENT_BTRL;
		
	if(STRCEQ(s, "RM90") || 
	   STRCEQ(s, "Landscape") ||
	   STRCEQ(s, "rotated-clockwise") ||
	   STRCEQ(s, "rcw"))
		return MDVI_ORIENT_RM90;
		
	if(STRCEQ(s, "RP90") || 
	   STRCEQ(s, "Seascape") ||
	   STRCEQ(s, "rotated-counter-clockwise") ||
	   STRCEQ(s, "rccw"))
		return MDVI_ORIENT_RP90;
		
	if(STRCEQ(s, "IRP90") || 
	   STRCEQ(s, "FlipSeascape") ||
	   STRCEQ(s, "flipped-seascape") ||
	   STRCEQ(s, "frccw"))
		return MDVI_ORIENT_IRP90;
		
	if(STRCEQ(s, "IRM90") || 
	   STRCEQ(s, "FlipLandscape") ||
	   STRCEQ(s, "flipped-landscape") ||
	   STRCEQ(s, "frcw"))
		return MDVI_ORIENT_IRM90;
		
	warning(_("unknown orientation `%s'\n"), s);
	return MDVI_ORIENT_TBLR;
}

/* 
 * this will try $NAME, and then `NAME' in texmf.cnf, with 
 * letters converted to lowercase, and _ replaced by -
 * (so MDVI_HDRIFT -> mdvi-hdrift)
 */
char	*mdvi_getenv(const char *name)
{
	static char kname[64];
	const char *ptr;
	int	i;
		
	if((ptr = getenv(name)) != NULL)
		return (char *)ptr;
	for(i = 0, ptr = name; *ptr; i++, ptr++)
		kname[i] = (*ptr == '_' ? '-' : tolower(*ptr));
	kname[i] = 0;
	return kpse_cnf_get(kname);
}

int	mdvi_getint(const char *name, long *value)
{
	long	x;
	char	*end;
	
	errno = 0;
	x = strtol(name, &end, 0);
	if(errno || *end)
		return -1;
	if(value) *value = x;
	return 0;
}

int	mdvi_getfloat(const char *name, double *value)
{
	long	x;
	char	*end;
	
	errno = 0;
	x = strtod(name, &end);
	if(errno || *end)
		return -1;
	if(value) *value = x;
	return 0;
}

int	mdvi_getenv_int(const char *name, int dflt)
{
	char	*var = mdvi_getenv(name);
	long	x;
	
	if(var == NULL) {
		DEBUG((DBG_VARS, "getenv_int: %s -> (nil)\n",
			name));
		return dflt;
	}
	if(mdvi_getint(var, &x) == -1) {
		warning(_("variable %s should be an integer\n"), name);
		x = dflt;
	}
	DEBUG((DBG_VARS, "getenv_int: $%s -> %ld (\"%s\")\n",
		name, x, var));
	return (int)x;
}

char	*mdvi_getenv_string(const char *name, char *dflt)
{
	char	*var = mdvi_getenv(name);
	
	if(var == NULL) {
		DEBUG((DBG_VARS, "getenv_string: %s -> (nil)\n",
			name));
		return dflt;
	}
	DEBUG((DBG_VARS, "getenv_string: $%s -> \"%s\"\n",
		name, var));
	return var;
}

double	mdvi_getenv_double(const char *name, double dflt)
{
	char	*var = mdvi_getenv(name);
	double	x;
	
	if(var == NULL) {
		DEBUG((DBG_VARS, "getenv_double: %s -> (nil)\n",
			name));
		return dflt;
	}
	if(mdvi_getfloat(var, &x) == -1) {
		warning(_("variable %s should be a floating-point number\n"),
			name);
		x = dflt;
	}
	DEBUG((DBG_VARS, "getenv_double: $%s -> %g (\"%s\")\n",
		name, x, var));
	return x;
}

DviAppConfig *mdvi_init_app(const char *program, const char *progid)
{
	DviAppConfig *app;
	char	*value;

	/* get kpathsea going -- we need it here */
	kpse_set_program_name(program, progid);
	
	app = xalloc(DviAppConfig);

	app->program = (char *)program;
	value = strrchr(app->program, '/');
	if(value)
		app->program = value + 1;
		
	/* get defaults from the environment */
	app->params.dpi      = mdvi_getenv_int("MDVI_DPI", MDVI_DPI);
	app->params.vdpi     = mdvi_getenv_int("MDVI_VDPI", MDVI_VDPI);
	app->params.mag      = mdvi_getenv_double("MDVI_MAGNIFICATION", MDVI_MAGNIFICATION);
	app->params.density  = mdvi_getenv_int("MDVI_PIXEL_DENSITY", MDVI_DEFAULT_DENSITY);
	app->params.gamma    = mdvi_getenv_double("MDVI_GAMMA", MDVI_DEFAULT_GAMMA);
	app->params.flags    = MDVI_PARAM_ANTIALIASED;
	app->params.hdrift   = mdvi_getenv_int("MDVI_HDRIFT", -1);
	app->params.vdrift   = mdvi_getenv_int("MDVI_VDRIFT", -1);
	app->params.hshrink  = mdvi_getenv_int("MDVI_HSHRINK", -1);
	app->params.vshrink  = mdvi_getenv_int("MDVI_VSHRINK", -1);
	value         = mdvi_getenv_string("MDVI_ORIENTATION", MDVI_ORIENTATION);
	app->params.orientation = mdvi_getorient(value);
	app->fontspec      = mdvi_getenv_string("MDVI_FONTSPEC", NULL);
	app->fontunspec    = mdvi_getenv_string("MDVI_FONTOMIT", NULL);
	app->fgcolor       = mdvi_getenv_string("MDVI_FOREGROUND", MDVI_FOREGROUND);
	app->bgcolor       = mdvi_getenv_string("MDVI_BACKGROUND", MDVI_BACKGROUND);
	app->hmargin       = mdvi_getenv_string("MDVI_HMARGIN", MDVI_HMARGIN);
	app->vmargin       = mdvi_getenv_string("MDVI_VMARGIN", MDVI_VMARGIN);
	app->hrule_units   = mdvi_getenv_string("MDVI_HRUNIT", MDVI_HRUNITS);
	app->vrule_units   = mdvi_getenv_string("MDVI_VRUNIT", MDVI_VRUNITS);
	app->paper.name    = mdvi_getenv_string("MDVI_PAPER", MDVI_PAPERNAME);
	app->fallback_font = mdvi_getenv_string("MDVI_FALLBACK_FONT", MDVI_FALLBACK_FONT);
	app->mfmode        = mdvi_getenv_string("MDVI_MFMODE", MDVI_MFMODE);
	app->page_sort     = MDVI_PAGE_SORT_NONE;
	app->page_ranges   = NULL;

	if(app->params.hshrink == -1 && app->params.vshrink == -1) {
		app->params.hshrink = 
		app->params.vshrink = mdvi_getenv_int("MDVI_SHRINKING",
			MDVI_DEFAULT_SHRINKING);
	}
	return app;
}

int	mdvi_check_config(DviAppConfig *app)
{
	/* Check all the values */

	if(mdvi_get_paper_size(app->paper.name, &app->paper) == -1) {
		warning(_("%s: unknown paper `%s', using %s\n"),
			app->program, app->paper.name,
			MDVI_PAPERNAME);
		mdvi_get_paper_size(MDVI_PAPERNAME, &app->paper);
	}

	if(app->params.dpi == (Uint)-1) {
		error(_("DPI must be a positive integer\n"));
		return -1;
	}
	if(app->params.vdpi == (Uint)-1)
		app->params.vdpi = app->params.dpi;
	if(app->params.hshrink == -1)
		app->params.hshrink = MDVI_SHRINK_FROM_DPI(app->params.dpi);
	if(app->params.vshrink == -1)
		app->params.vshrink = MDVI_SHRINK_FROM_DPI(app->params.dpi);
	if(app->params.mag <= 0) {
		error(_("magnification must be a positive number\n"));
		return -1;
	}
	if(app->params.density < 0 || app->params.density > 100) {
		warning(_("pixel density must be between 0 and 100\n"));
		app->params.density = (app->params.density < 0) ? 0 : 100;
	}
	if(app->fgcolor == NULL)
		app->fgcolor = "black";
	if(app->bgcolor == NULL)
		app->bgcolor = "white";
		
	/* we must have a fallback font */
	if(app->fallback_font == NULL) {
		warning(_("no fallback font specified, using `%s'\n"),
			MDVI_FALLBACK_FONT);
		app->fallback_font = MDVI_FALLBACK_FONT;
	}

	/* finish initializing kpathsea */
	kpse_init_prog(app->program, app->params.dpi,
		app->mfmode, NULL);
	kpse_set_program_enabled(kpse_any_glyph_format, 1, kpse_src_compile);
	kpse_set_program_enabled(kpse_pk_format, 1, kpse_src_compile);
	kpse_set_program_enabled(kpse_tfm_format, 1, kpse_src_compile);
	kpse_set_program_enabled(kpse_ofm_format, 1, kpse_src_compile);
	if(_mdvi_debug_mask & DBG_PATHS)
		KPSE_DEBUG_SET(KPSE_DEBUG_PATHS);
	if(_mdvi_debug_mask & DBG_VARS)
		KPSE_DEBUG_SET(KPSE_DEBUG_VARS);
	if(_mdvi_debug_mask & DBG_SEARCH)
		KPSE_DEBUG_SET(KPSE_DEBUG_SEARCH);
		
	return 0;
}

void	mdvi_init_kpathsea(const char *program, 
	const char *mfmode, const char *font, int dpi)
{
	const char *p;
	

	p = strrchr(program, '/');
	p = (p ? p + 1 : program);
	kpse_set_program_name(program, p);
	kpse_init_prog(p, dpi, mfmode, font);
	kpse_set_program_enabled(kpse_any_glyph_format,
		1, kpse_src_compile);
	kpse_set_program_enabled(kpse_pk_format,
		1, kpse_src_compile);
	kpse_set_program_enabled(kpse_tfm_format,
		1, kpse_src_compile);
	kpse_set_program_enabled(kpse_ofm_format,
		1, kpse_src_compile);
}

void	mdvi_set_fallback_font(const char *name)
{
	if(_mdvi_fallback_font) {
		xfree(_mdvi_fallback_font);
		_mdvi_fallback_font = NULL;
	}
	if(name)
		_mdvi_fallback_font = xstrdup(name);
}

char	*mdvi_get_fallback_font(void)
{
	return _mdvi_fallback_font ? xstrdup(_mdvi_fallback_font) : NULL;
}