// Local configuration
#include "config.h"

// Implementation
#include "CharsetMagic.hpp"

// STDC++
#include <memory>
#include <vector>

// SYSTEM C

// Local
#include "Exception.hpp"

namespace UI {
namespace Util {
namespace CharsetMagic {

// From "file", somewhat adjusted.
namespace File
{
#include "ascmagic.c"
}

bool looksLikeASCII(char const * const buf, size_t const & len)
{
	std::vector<File::unichar> ubuf(len+1);
	size_t ulen;
	return File::looks_ascii((unsigned char *)buf, len, &ubuf[0], &ulen) != 0;
}

bool looksLikeUTF8(char const * const buf, size_t const & len)
{
	std::vector<File::unichar> ubuf(len+1);
	size_t ulen;
	return File::looks_utf8((unsigned char *)buf, len, &ubuf[0], &ulen) != 0;
}

bool looksLikeLatin1(char const * const buf, size_t const & len)
{
	std::vector<File::unichar> ubuf(len+1);
	size_t ulen;
	return File::looks_latin1((unsigned char *)buf, len, &ubuf[0], &ulen) != 0;
}

bool looksLikeUTF16LE(char const * const buf, size_t const & len)
{
	std::vector<File::unichar> ubuf(len+1);
	size_t ulen;
	return File::looks_unicode((unsigned char *)buf, len, &ubuf[0], &ulen) == 1;
}

bool looksLikeUTF16BE(char const * const buf, size_t const & len)
{
	std::vector<File::unichar> ubuf(len+1);
	size_t ulen;
	return File::looks_unicode((unsigned char *)buf, len, &ubuf[0], &ulen) > 1;
}

typedef bool (* LooksLikeFunc) (char const * const, size_t const &);
typedef std::pair<LooksLikeFunc, std::string> LooksLikePair;
typedef std::vector<LooksLikePair > LooksLikePairVec;

// This determines available "looks like" tests and their order
LooksLikePairVec const genLooksLikePairs()
{
	LooksLikePairVec result;
	result.push_back(std::make_pair(&looksLikeASCII,   "ASCII"));
	result.push_back(std::make_pair(&looksLikeUTF8,    "UTF-8"));
	result.push_back(std::make_pair(&looksLikeUTF16LE, "UTF-16LE"));
	result.push_back(std::make_pair(&looksLikeUTF16BE, "UTF-16BE"));
	// This will also detect UTF-16 as latin, so this must come after utf16 tests
	result.push_back(std::make_pair(&looksLikeLatin1,  "ISO-8859-15"));
	return result;
}

// The actual static test vector
static LooksLikePairVec const LooksLikePairs(genLooksLikePairs());

std::string guess(char const * const buf, size_t const & len)
{
	for (LooksLikePairVec::const_iterator f(LooksLikePairs.begin()); f != LooksLikePairs.end(); ++f)
	{
		if (f->first(buf, len))
		{
			return f->second;
		}
	}
	return "";
}

std::string guess(std::string const & buf, std::string::size_type const & len)
{
	return guess(buf.c_str(), len == std::string::npos ? buf.size() : len);
}

}}}
