/**
 * \file FontInfo.C
 * This file is part of LyX, the document processor.
 * Licence details can be found in the file COPYING.
 *
 * \author Asger Alstrup
 * \author John Levon
 *
 * Full author contact details are available in file CREDITS.
 */

#include <config.h>

#include "FontInfo.h"

#include "debug.h"
#include "lyxrc.h"	// lyxrc.use_scalable_fonts

#include "frontends/lyx_gui.h"

#include "support/lstrings.h"
#include "support/lyxlib.h"
#include "support/convert.h"

#include "lyx_forms.h"

#include <cmath>

using std::abs;
using std::endl;
using std::string;

namespace lyx {

using support::token;

namespace frontend {

/// Load font close to this size
string const FontInfo::getFontname(int size)
{
	if (!exist())
		return string();

	int closestind = -1;
	double error = 100000.0;

	for (int i = 0; i < matches; ++i) {
		if (sizes[i] == 0) {
			// Scalable font should not be considered close
		} else if (sizes[i] == size) {
			lyxerr[Debug::FONT] << "Exact font match with\n"
					    << strings[i] << endl;
			return strings[i];
		} else if (abs(sizes[i] - size - 0.1) < error) {
			error = abs(sizes[i] - size - 0.1);
			closestind = i;
		}
	}

	if (scalable && (lyxrc.use_scalable_fonts || closestind == -1)) {
		// We can use scalable
		string const font = resize(strings[scaleindex], size);
		lyxerr[Debug::FONT] << "Using scalable font to get\n"
				    << font << endl;
		return font;
	}

	// Did any fonts get close?
	if (closestind == -1) {
		// No, so...
		return string();
	}

	// We use the closest match
	lyxerr[Debug::FONT] << "Using closest font match to get size "
			    << size
			    << " with\n" << strings[closestind] << endl;
	return strings[closestind];
}


/// Build newly sized font string
string const FontInfo::resize(string const & font, int size) const
{
	string ret(font);
	// Find the position of the size spec
	int cut = 0;
	string::iterator before = string::iterator(0);
	string::iterator after = string::iterator(0);
	for (string::iterator sit = ret.begin();
	     sit != ret.end(); ++sit)
		if ((*sit) == '-') {
			++cut;
			if (cut == 7) before = sit + 1;
			else if (cut == 8) {
				after = sit;
				break;
			}
		}
	ret.replace(before, after, convert<string>(size));
	return ret;
}


/// Set new pattern
void FontInfo::setPattern(string const & pat)
{
	init();
	pattern = pat;
}


/// Query font in X11
void FontInfo::query()
{
	if (queried)
		return;

	queried = true;

	if (pattern.empty()) {
		lyxerr << "Cannot use empty font name for font query."
		       << endl;
		return;
	}

	char ** list = 0;
	if (lyx_gui::use_gui)
		list = XListFonts(fl_get_display(), pattern.c_str(),
				  100, &matches);

	if (list == 0) {
		// No fonts matched
		scalable = false;
		sizes.reset();
	} else {
		sizes.reset(new int[matches]);
		strings.reset(new string[matches]);

		// We have matches. Run them through
		for (int i = 0; i < matches; ++i) {
			string name(list[i]);
			lyxerr[Debug::FONT] << "match #" << i << ' '
					    << name << endl;
			sizes[i] = convert<int>(token(name, '-', 7));
			strings[i] = name;
			if (sizes[i] == 0) {
				if (scaleindex == -1) {
					scaleindex = i;
				}
				scalable = true;
			} else if (convert<int>(token(name, '-', 12)) == 0)
				// Ignore bogus matches of scalable fonts.
				sizes[i] = 0;
		};
		XFreeFontNames(list);
	}
}


void FontInfo::init()
{
	sizes.reset();
	strings.reset();
	matches = 0;
	queried = false;
	scalable = false;
	scaleindex = -1;
}

} // namespace frontend
} // namespace lyx
